Quote:Original post by Melekor
I'm intrigued. Can you explain why it's bad design and also what the alternative is? (maybe give an example?) I use a lot of them so if I could be designing my stuff better, I'd love to know how.
First, I would specify what a setter is. It's a member method in a class which is equivalent, in functionality and description (and possibly in implementation) to assigning the arguments to one or several member variables of that class, and which advertises to the users of the class the existence of those variables. So, in the following example, set_width and set_dimensions are setters:
class rect { int w, h;public: void set_dimensions(int w, int h) { this -> w = w; this -> h = h; } void set_width(int w) { this -> w = w; }};
On the other hand, functions such as std::vector<T>::resize are not setters, because they perform other operations in addition to altering a single value.
Now, why do I find setters to be an indicator of bad design? Because they only work if the class is a product type (that is, a list of properties which are more or less individually accessible). So, from there, I see two possibilities: first, the class provides nothing else, aside from that list of properties, at which point perhaps dropping the properties and making the class a structure with public members would achieve the same effect with less repetitiveness:
struct rect { int w, h; bool operator bool () const { return (w >= 0) && (h >= 0); }};
Or the class does something aside from providing those properties, at which point it violates the single responsibility principle, and I would suggest separating the product type functionality into one class (such as "configuration" or "options") and leaving the rest of the functionality in the original class.
Note that I did not say setters are bad design. They do have their uses, for instance when providing alternate ways of accessing properties (see, for instance, a mathematical vector class where subscripting is provided as an alternative). They are, however, indicators of bad design because they most frequently appear in such designs, for a simple reason: when the class was designed from the inside out. In object oriented programming, it is in general best to design the interface of a class first, and only then to write its implementation (altering the interface only if major issues prevent you from sanely implementing it). Setters, however, are property advertiser: "What
is inside the class?" as opposed to the more relevant "What does the class
do?" question.
My proposed alternative is to design the class in terms of usage. You almost never want to set the health of a character by a given amount; you usually want to inflict or heal a certain amount of damage. In fact, in my current game, I can spawn, own, kill, think, render, loop, schedule, place, damage, heal, stop, reset, order, send and direct, but the only thing I can set is the X, Y and Z coordinates of my vector (an eminent case of bad design, since I use subscripting anyway).