I am doing a final project in a C++ class writing a very simple usenet-like client/server. I figure that since it's usenet-like I'll have a NewsGroup class and an Article class, I'm now working on my Article class. I can't really decide on a good design, though (this class is not about design patterns and I haven't taken any).

This is what I have:

class Article {
    const std::string author;
    std::string title;
    std::string text;
    const uint32_t id;
    system_clock::time_point timestamp;

    Article(const std::string auth&,
            const std::string tit&,
            const std::string txt&,
            const system_clock::time_point&);

    Article(const Article&);
    void operator=(const Article&);
    static uint32_t id_pool;

My motivation is this:

author should never change -> const

title could change if edited -> non-const

text could change if edited -> non-const

id should never change -> const

timestamp could change but probably shouldn't, I'm not sure what to do with it yet.

id_pool is just where I get IDs from. One specification is that IDs should never be reused so I just increment id_pool in the Article constructor.

Coming from Java with all the getters and setters that I really don't like, and then some Python with it's "Everything public" and properties, that I do like, I'm getting a bit confused here.

I mean, I could make the members private and have getters and setters (I can't think of any natural "verb-methods" that an Article can "do"), but it feels like I would gain very little.

I would be thankful for some pointers on good design in this case.

  • If the server is to exchange message with others, your messages must remember their Message IDs, to avoid duplicates. Also, you really want threading in Usenet, so you need message id and references. On the other hand, the concept of “editing” a message after it has been sent is totally alien to Usenet. – Christopher Creutzig Mar 11 '13 at 21:49
  • As I said, this is a very simple implementation, so threading should not be implemented. – evading Mar 11 '13 at 21:51
  • Well, but if the specification asks explicitly about “Usenet server”, you still have to behave like one. You cannot discard the original message ID (looks like an E-Mail address), you need to support crosspostings, and should you ever discard header information, better make sure you never forward that crippled message to any other server. It's probably a good idea to read up on the standard message format - and seriously consider implementing an NNTP interface, too. – Christopher Creutzig Mar 11 '13 at 21:55
  • You may find RFC 977 and RFC 3977 useful. The original one may be a bit simpler to read as many things weren't needed to be considered in those days. – user40980 Mar 11 '13 at 22:16
  • 1
    @refuser you have changed it from "usenet client/server" to "usenet like client/server." The first had a very well defined set of requirements. Your change has made it so one doesn't know what the requirements for the system are. These requirements directly impact the question of is your design a good one. Will you be able to edit messages? Cross post to multiple groups? Support threading? Exchange messages between multiple servers? Cancel messages? Create new news groups? Other control type activities? All of these questions impact the design of an article class. – user40980 Mar 12 '13 at 2:47

Start with the interface you want the class to expose to its users. Do not think immediately about the implementation, e.g., whether to use std::string for the title, etc. I would come up with something like below:

class Article {
    typedef implementation_defined Id;

    Article(const char* author, const char* title);

    Id GetId() const;
    const char* GetAuthor() const;
    const char* GetTitle() const;
    const char* GetText() const;
    system_clock::time_point GetTime() const;

    void SetTitle(const char* text);
    void SetText(const char* text);
    void SetTime(system_clock::time_point timestamp);

The intention is that the caller should use the type Article::Id instead of something like int. I assume the Id is uniquely generated on creation, the text can be empty, and the default timestamp is the current time.

As you are not exposing the implementation to the caller, you are free to change the implementation later. E.g., maybe the interface dictates the UTF-8 encoding, but the real implementation uses UTF-16 (wchar_t) on Windows (just to show, not that it is something you should/want to do). You can also make some checks in the Set... methods.

This might be trivial, but I think the principle is that you need to: 1) think from the user of the class; 2) make it flexible and reduce the dependency.

| improve this answer | |

For starters it would make sense to make the member variables private and expose public get/set functions where necessary. The advantage this provides is that you could then modify the internal member variables if necessary (future refactoring, say) without having to change the calling contexts because the internals are hidden behind the external class interface.

This would generally be considered good extensible, encapsulated design in any language when working on an object oriented project that you plan to maintain.

| improve this answer | |
  • Moreover, providing for example only "getters" for your const fields is more intention revealing for the users of your class than getting an error because they are trying to set a const field. – Tallmaris Mar 13 '13 at 10:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.