Reputation: 341
For example, I create a Button class. Button
should have its own text (with color, size, font, spacing, etc.), states and background.
Because text labels are useful even in another widgets (text labels, text edits, etc.) I put all needed in another class (call it Label
).
Background color is useful too, so I created another class - Color
with all needed methods - changing, comparing...
Now come back to Button class.
class Button {
private:
Color _bgColor;
Label _text;
/* another private members */
public:
/* Content of Button class */
};
But what if I would like to change the button background color? In this case, I need to write another two methods => setColor
and getColor
. In fact, I have to write all methods which are defined for Color
class.
Another option is to define private classes as public and access them like button.bgColor.setColor()
. But it seems weird to me to one time call button.disable
and another time button.color.setColor
.
Is there any other option which I don't know about? Thank you for help.
Upvotes: 0
Views: 515
Reputation: 19032
You're correct in that when something has attributes those attributes need to be exposed somehow, and that can lead to code bloat. However, as with all things a simple layer of abstraction can make things easier.
You can provide "helper classes" for these types of attributes and use them as mixins. This will keep the code as small as possible while still
class HasLabel
{
public:
void SetLabelText(const std::string& text);
const std::string& GetLabelText() const;
private:
Label label_;
};
class HasBackgroundColor
{
public:
void SetBackgroundColor(const Color& color);
const Color& GetBackgroundColor() const;
private:
Color color_;
};
class Button : private HasBackgroundColor, private HasLabel
{
public:
// Expose BkColor
using HasBackgroundColor::SetLabelText;
using HasBackgroundColor::GetLabelText;
// Expose Label
using HasLabel::SetLabelText;
using HasLabel::GetLabelText;
};
You could also use public inheritance and then the using
directives wouldn't be necessary, but whether that's acceptable (if a Button
truly "is-a" HasLabel
) is a matter of personal preference.
You could also use the CRTP to reduce the amount of boilerplate code for objects with similar mixins.
Upvotes: 1
Reputation: 157
But what if I would like to change the button background color? In this case, I need to write another two methods => setColor and getColor. In fact, I have to write all methods which are defined for Color class.
Why would you do that?
Just define a function SetBackgroundColor(Color &newColor)
for setting the color and const Color& GetBackgroundColor() const
for accessing it!
Upvotes: 1
Reputation: 11251
But what if I would like to change the button background color? In this case, I need to write another two methods =>
setColor
andgetColor
. In fact, I have to write all methods which are defined forColor
class.
Not true. You only need to write those two methods. Anything else just happens through the getColor
return value. For example, to test if two buttons have the same color, you'd write:
if (button1.getColor() == button2.getColor())
not
if (button1.hasSameColor(button2))
That is, unless you want to hide Button
's use of the Color
class as an "implementation detail." I wouldn't recommend that. Programs dealing with color should usually treat colors as a value type, akin to plain numbers, points, vectors, etc.
Upvotes: 0