
Originally Posted by
marcvanriet
Sure, but all depends on the situation. What if you then come across a bike of which the front light can be set to three states : on - blinking - off. And when there are multiple independently controlled lights in the chamber ?
Then you extend the Lightable interface. What you say applies to any class, inheritance, single or multiple, is irrelevant here. If you continue this way, you'll reach a conclusion that there is no point in creating classes at all because some day you might want to change something in your program breaking what you did before.
I would probably prefer an interface like
bike1->frontlight->enableLight();
room1->ceilinglight->disableLight();
room1->curtainlights->enableLight();
If the 'frontlight' and so have a reference to the class of which they are member, events can be triggered when a light status changes if this is necessary.
This changes nothing really. You still have to be able to know that some object has a "frontlight", "ceilinglight" and "curtainlight" members and that some other has none of them. The point is to have a common base class and then say "if this object has a ceiling light, turn it on". For that you can use double dispatch.
Or in terms of C++:
class Visitor {
public:
virtual void visitLivingRoom(LivingRoom *) {};
virtual void visitBike(Bike *) {};
};
class Item {
public:
virtual void accept(Visitor &visitor) = 0;
};
class LivingRoom : public Item {
public:
void accept(Visitor &visitor) { visitor.visitLivingRoom(this); }
};
class Bike : public Item {
public:
void accept(Visitor &visitor) { visitor.visitBike(this); }
};
class Visitor {
public:
virtual void visitLivingRoom(LivingRoom *) {};
virtual void visitBike(Bike *) {};
};
class Item {
public:
virtual void accept(Visitor &visitor) = 0;
};
class LivingRoom : public Item {
public:
void accept(Visitor &visitor) { visitor.visitLivingRoom(this); }
};
class Bike : public Item {
public:
void accept(Visitor &visitor) { visitor.visitBike(this); }
};
To copy to clipboard, switch view to plain text mode
And then:
class TurnLightsOnBikes : public Visitor {
public:
void visitBike(Bike *bike) { bike->turnLightsOn(); }
};
QList<Item*> items = ...
TurnLightsOnBikes bVisitor;
foreach(Item *item, items) {
item->accept(bVisitor);
}
class TurnLightsOnBikes : public Visitor {
public:
void visitBike(Bike *bike) { bike->turnLightsOn(); }
};
QList<Item*> items = ...
TurnLightsOnBikes bVisitor;
foreach(Item *item, items) {
item->accept(bVisitor);
}
To copy to clipboard, switch view to plain text mode
Since C++ doesn't have double dispatch (only single dispatch through virtual methods) it has to be emulated like in the code above. Furthermore the visitor can be made a friend of Item subclasses to allow access to private members.
In the "adding more lights" case it is enough to modify the visitor or create a new one. When a new subclass of Item is added, it is enough to add a new method to the Visitor interface. In all cases the Item class API remains clean and functionality is added by implementing a new Visitor subclass (which gives a nice separation and extendability).
Bookmarks