I have a task to implement fluent interface for a class, which consist of other classes. Let's say we have a class:
class Pizza {
int price, size;
}
class Foo {
string name;
Pizza p1, p2;
}
I would like to use code like:
Foo f = FooBuilder().setName("foo")
.settingP1().setPrice(5).setSize(1)
.settingP2().setPrice(2)
.build();
but I also would like to forbid code like:
Foo f = FooBuilder().setName("foo").setPrice(5);
I thought about a class inherited from FooBuilder which is returned after calling .settingP1() but I am not sure how to do it. Notice that I don't want to write .build() when I ended specifying Pizza object.
EDIT: Maybe I should've mentioned that when I wrote .settingP2().setPrice(2) without writing .setSize(sth) I meant that size will just have default value. I want to be able to "jump" to the next object regardless of specifying all attributes or not
EDIT2: I know how to implement the Builder pattern and fluent interface for classes which have fields of basic types. The problem is I want the code
Foo f = FooBuilder().setName("foo").setPrice(5);
to not compile. Maybe it's impossible to write such a builder.
If you don't mind, I'll write solution for your problem in Java, hopefully you'll be able to apply it in C++ without anyu problem.
You have 2 options.
More verbose DSL (I prefer not to call your problem Builder any more, but either Fluent API, or DSL - Domain Specific Language, as it defines grammar rules for it) with simpler implementation
or simpler DSL (exactly what you wrote) with a small trick in the implenmentation.
For optiona #1 your usage would look like this:
new FooBuilder().setName("Foo")
.settingP1().setPrice(5).setSize(1).end()
.settingP2().setPrice(2).end()
.build();
Notice additional methods end(). Corresponding code in Java would look like this:
public class FooBuilder {
public FooBuilder setName(String name) {
// Store the name
return this;
}
public PizzaBuilder settingP1() {
return new PizzaBuilder(pizza1, this);
}
public PizzaBuilder settingP2() {
return new PizzaBuilder(pizza2, this);
}
public Foo build() {
// return Foo build using stored information
}
}
public class PizzaBuilder {
private final Pizza pizza;
private final FooBuilder foo;
// Constructor
public PizzaBuilder(Pizza pizza, FooBuilder foo) {
this.pizza = pizza;
this.foo = foo;
}
public PizzaBuilder setPrice(int price) {
// update pizza price
return this;
}
public PizzaBuilder setSize(int size) {
// update pizza size
return this;
}
// With this method you return to parent, and you can set second pizza.
public FooBuilder end() {
return foo;
}
}
Now for option #2 I'd do another generalization to your problem to allow defining any number of pizzas. I'd also omit set prefix, it's not usual for DSL:
new FooBuilder().name("Foo")
.addPizzaWith().price(5).size(1)
.addPizzaWith().price(2)
.build();
Now the implementation will look like:
public class FooBuilder {
public FooBuilder(String name) {
// Store name
return this;
}
public PizzaBuilder addPizzaWith() {
Pizza pizza = createAndStorePizza(); // Some private method to do what is says
return new PizzaBuilder(pizza, this);
}
public Foo build() {
// Build and return the Foo using stored data
}
}
public class PizzaBuilder {
private final Pizza pizza;
private final FooBuilder foo;
public PizzaBuilder(Pizza pizza, FooBuilder foo) {
this.pizza = pizza;
this.foo = foo;
}
public PizzaBuilder price(int value) {
// Store price value
return this;
}
public PizzaBuilder size(int value) {
// Store size value
return this;
}
// This method does the trick - it terminates first pizza specification,
// and delegates entering second (or any other) pizza specification to
// the parent FooBuilder.
public PizzaBuilder addPizzaWith() {
return foo.addPizzaWith();
}
// Another similar trick with allowing to call build directly on Pizza
// specification
public Foo build() {
return foo.build();
}
}
There is one noticeable attribute - circular dependency. FooBuilder must know PizzaBuilder, and PizzaBuilder must know FooBuilder. In Java it's not an issue.
If I remember correctly, you can solve it in C++ too by declaring first just the
type using forward declaration or so.
It would also be typically beneficial for the second example in Java to introduce an interface with methods build() and addPizzaWith(), which both classes implement. So you can e.g. add pizzas in cycle without any issue.
Dmitri Nesteruk has written a "facet builder" example that is pretty much what you are trying to achieve.
The basic structure would be something like (almost pseudo code):
class FooBuilderBase {
protected:
Foo& foo; // reference to derived builders
FooBuilderBase(Foo& f) : foo(f) {}
public:
PizzaBuilder settingP1() { return PizzaBuilder(foo, foo.p1); }
PizzaBuilder settingP2() { return PizzaBuilder(foo, foo.p2); }
};
class FooBuilder : public FooBuilderBase {
Foo foo_; // real instance
public:
FooBuilder() : FooBuilderBase(foo_) {}
FooBuilder& setName(string n) { foo.name = n; return *this; }
};
class PizzaBuilder : public FooBuilderBase {
Pizza& pizza;
public:
PizzaBuilder(Foo& f, Pizza& p) : FooBuilderBase(f), pizza(p) {}
PizzaBuilder& setPrice(int p) { pizza.price = p; return *this; }
};
You can add a FooPizzaBuilder class as derrivate of FooBuilder.
By doing this you seperate the building of your Pizza classes and the building of the actual Foo class.
Consider the following code:
enum class PizzaNum {
ONE, TWO
}
class FooPizzaBuilder;
class FooBuilder {
public:
FooBuilder();
FooBuilder setName();
FooPizzaBuilder settingP1();
FooPizzaBuilder settingP2();
Foo build();
protected:
void _setPrize(PizzaNum); //Don't expose _setPrice() to user
void _setSize(PizzaNum); //Don't expose _setSize() to user
}
class FooPizzaBuilder : public FooBuilder {
public:
FooPizzaBuilder(PizzaNum pizzaNum)
FooPizzaBuilder setPrice(); //Call _setPrice()
FooPizzaBuilder setSize(); //Call _setSize()
}
This requires you to call settingP1() before making a call to setPrice();
An easy way to make the code type safe is to add an enum class to FooBuilder.
class FooBuilder {
public:
enum class PizzaNum {
ONE,
TWO
}
}
and...
FooBuilder& FooBuilder::setPrice(const PizzaNum pizzaNum, const int price) {
switch (pizzaNum) {
case PizzaNum::ONE:
p1.setPrice(price);
break;
case PizzaNum::TWO:
p2.setPrice(price);
break;
}
return this;
}
Then, you need to pass the enum to the method otherwise it results in a compile time error (e.g. .setPrice(FooBuilder::PizzaNum::ONE, 5).
Note, this is non-variadic.
Related
In our c++ application, we create many objects, like this:
class Interface {
public:
static InterfaceImplementation Create(string s) {
return InterfaceImplementation(s);
}
};
class User {
public:
User() {
i = Interface::Create("User");
}
private:
Interface i;
};
Please note here, that the "User" class name and the string provided for the interface implementation match.
I would like to refactor this "pattern" and inject the interface by using e.g. Boost::ex.DI framework, but I haven't found, how to tell to the framework, to "inject instance with specific value"
class Interface {
};
class InterfaceImplementation : public Interface {
public:
InterfaceImplementation(string s) {
}
};
class User {
public:
User(<Interface implementation object created by string "User">) {
}
};
class Square {
public:
Square(<Interface implementation object created by string "Square">) {
}
};
Sorry, if I missed something from the documentation.
I am getting an issue for retrieving BaseClass correct enum value.
class BaseClass
{
public:
enum EntityId {
EN_NONE = 0,
EN_PLAYER = 1,
EN_PLATFORM,
EN_GROUND,
EN_OBSTACLE,
EN_OTHER
};
void setEntityId(EntityId id) { _Entityid = id; }
EntityId getEntityId() { return _Entityid; }
protected:
EntityId _Entityid;
};
and
class DeriveredClassA : public SomeClass, public BaseClass {....};
class DeriveredClassB : public SomeClass, public BaseClass {....};
The initialization goes like this
DeriveredClassA->setEntityId(BaseClass::EntityId::EN_PLAYER);
DeriveredClassB->setEntityId(BaseClass::EntityId::EN_OBSTACLE);
Which is placed into a different vector list correspoinding to that enum.
However, I am forced to use void* to do static_casts cats...
Like this:
BaseClass* EA = static_cast<BaseClass*>(bodyUserDataA); //bodyUserDataA and bodyUserDataB are both void*
BaseClass* EB = static_cast<BaseClass*>(bodyUserDataB);
And I am trying to retrieve using EA->getEntityId() and EB->getEntityId() so I could check which one is EN_PLAYER, which one is EN_GROUND and etc. So then I could up-class from base into derivered class and do other stuff with it.
Tried using with virtual, however somehow I am receiving 2 copies of _EntityID, which can be either the same or DIFFERENT between my Derivered and BaseClass of that one object.
Moreover, I can't cast right away into DeriveredClass, since the code checking would be huge, due to many different types of DeriveredClass'es (DeriveredClassA, DeriveredClassB, DeriveredClassC, DeriveredClassD) with their corresponding vector list.
My question is that How I need setup correctly both Base and Derivered class, so that I could access _EntityID from Baseclass which is the same of that DeriveredClass? My main problem might is that I used incorectly virtual functions, so I left on default to understand my issue.
P.S. This is mainly my c++ issue, other tags are added due to I am using game engine and physics engine for this case.
I believe that you want your code to look more like this:
class Entity
{
public:
enum Type {
EN_NONE = 0,
EN_PLAYER = 1,
EN_PLATFORM,
EN_GROUND,
EN_OBSTACLE,
EN_OTHER
};
Type getType() { return _type; }
protected:
Entity(Type type): _type(type) {}
private:
const Type _type;
};
Then your derived classes and usage of this base would be more like:
class PlayerEntity: public Entity, public SomeClass
{
public:
PlayerEntity(std::string name): Entity(EN_PLAYER), _name(name) {}
std::string getName() const { return _name; }
private:
std::string _name;
};
class PlatformEntity: public Entity, public SomeClass
{
public:
PlatformEntity(): Entity(EN_PLATFORM) {}
};
Initialization is then done like:
int main()
{
PlatformEntity platform;
std::vector<PlatformEntity> platforms(platform);
std::vector<PlayerEntity> players;
players.emplace_back("Bob");
players.emplace_back("Alice");
players.emplace_back("Ook");
}
Access from user-data could then look like this:
// bodyUserDataA and bodyUserDataB are both void*
Entity* const EA = static_cast<Entity*>(bodyUserDataA);
Entity* const EB = static_cast<Entity*>(bodyUserDataB);
switch (EA->getType())
{
case Entity::EN_PLAYER:
{
PlayerEntity* player = static_cast<PlayerEntity*>(EA);
std::cout << "Found player: " << player->getName();
break;
}
case Entity::EN_OTHER:
...
default:
break;
}
We are writing a generic middleware for the gadget- DTV. We have a module called ContentMgr, which is a base class. Now, for the different customer needs, we have the VideoconContentMgr ( for instance)- which is derived from ContentMgr.
class ContentMgr
{
public:
virtual void setContent()
{
cout<<"Unused function";
}
};
class VideoconContentMgr: public ContentMgr
{
virtual void setContent()
{
cout<<"Do some useful computation;
}
};
client code - based on the product type - the
/** if the product is generic **/
ContentMgr *product = new ContentMgr();
/** If the product is videocon **/
ContentMgr *product = new VideoconContentMgr();
My question is according to the Interface Segregation Principle - One should avoid fat/polluted interfaces. How can I avoid the polluted method - setContent() here. For the generic product,setContent() is not useful. However, for the videocon product it is useful. How can I avoid the fat/polluted method setContent()?
For the generic product, setContent() is not useful. However, for the videocon product it is useful.
One solution is to keep the member function where it is useful - put it into VideoconContentMgr only, and use it in the context specific to the VideoconContentMgr subtype:
/** if the product is generic **/ ContentMgr *product = new ContentMgr();
/** If the product is videocon **/ {
VideoconContentMgr *vcm = new VideoconContentMgr();
vcm->setContent();
ContentMgr *product = vcm;
}
If the usefulness of the member function specific to a subclass extends past the initialization time, use a visitor-like approach. Subclass-specific code remains bound to subclasses, but now you add a visitor that does nothing for a generic class, and calls setContent() on VideoconContentMgr class:
struct ContentMgrVisitor {
virtual void visitGeneric(ContentMgr& m) {};
virtual void visitVideo(VideoconContentMgr& vm) {};
};
struct ContentMgr
{
virtual void accept(ContentMgrVisitor& v)
{
v.visitGeneric(this);
}
};
struct VideoconContentMgr: public ContentMgr
{
virtual void setContent()
{
cout<<"Do some useful computation;
}
virtual void accept(ContentMgrVisitor& v)
{
v.visitVideo(this);
}
};
Now a client who wants to call setContent can do it from a visitor:
class SetContentVisitor : public ContentMgrVisitor {
void visitVideo(VideoconContentMgr& vm) {
vm.setContent();
}
};
...
ContentMgr *mgr = ... // Comes from somewhere
SetContentVisitor scv;
mgr->accept(scv);
BIG EDIT
So after gathering some feedback from all of you, and meditating on the XY problem as Zack suggested, I decided to add another code example which illustrates exactly what I'm trying to accomplish (ie the "X") instead of asking about my "Y".
So now we are working with cars and I've added 5 abstract classes: ICar, ICarFeatures, ICarParts, ICarMaker, ICarFixer. All of these interfaces will wrap or use a technology-specific complex object provided by a 3rd party library, depending on the derived class behind the interface. These interfaces will intelligently manage the life cycle of the complex library objects.
My use case here is the FordCar class. In this example, I used the Ford library to access classes FordFeatureImpl, FordPartsImpl, and FordCarImpl. Here is the code:
class ICar {
public:
ICar(void) {}
virtual ~ICar(void) {}
};
class FordCar : public ICar {
public:
ICar(void) {}
~FordCar(void) {}
FordCarImpl* _carImpl;
};
class ICarFeatures {
public:
ICarFeatures(void) {}
virtual ~ICarFeatures(void) {}
virtual void addFeature(UserInput feature) = 0;
};
class FordCarFeatures : public ICarFeatures{
public:
FordCarFeatures(void) {}
virtual ~FordCarFeatures(void) {}
virtual void addFeature(UserInput feature){
//extract useful information out of feature, ie:
std::string name = feature.name;
int value = feature.value;
_fordFeature->specialAddFeatureMethod(name, value);
}
FordFeatureImpl* _fordFeature;
};
class ICarParts {
public:
ICarParts(void) {}
virtual ~ICarParts(void) {}
virtual void addPart(UserInput part) = 0;
};
class FordCarParts :public ICarParts{
public:
FordCarParts(void) {}
virtual ~FordCarParts(void) {}
virtual void addPart(UserInput part) {
//extract useful information out of part, ie:
std::string name = part.name;
std::string dimensions = part.dimensions;
_fordParts->specialAddPartMethod(name, dimensions);
}
FordPartsImpl* _fordParts;
};
class ICarMaker {
public:
ICarMaker(void) {}
virtual ~ICarMaker(void) {}
virtual ICar* makeCar(ICarFeatures* features, ICarParts* parts) = 0;
};
class FordCarMaker {
public:
FordCarMaker(void) {}
virtual ~FordCarMaker(void) {}
virtual ICar* makeCar(ICarFeatures* features, ICarParts* parts){
FordFeatureImpl* fordFeatures = dynamic_cast<FordFeatureImpl*>(features);
FordPartsImpl* fordParts = dynamic_cast<FordPartsImpl*>(parts);
FordCar* fordCar = customFordMakerFunction(fordFeatures, fordParts);
return dynamic_cast<ICar*>(fordCar);
}
FordCar* customFordMakerFunction(FordFeatureImpl* fordFeatures, FordPartsImpl* fordParts) {
FordCar* fordCar = new FordCar;
fordCar->_carImpl->specialFeatureMethod(fordFeatures);
fordCar->_carImpl->specialPartsMethod(fordParts);
return fordCar;
}
};
class ICarFixer {
public:
ICarFixer(void) {}
virtual ~ICarFixer(void) {}
virtual void fixCar(ICar* car, ICarParts* parts) = 0;
};
class FordCarFixer {
public:
FordCarFixer(void) {}
virtual ~FordCarFixer(void) {}
virtual void fixCar(ICar* car, ICarParts* parts) {
FordCar* fordCar = dynamic_cast<FordCar*>(car);
FordPartsImpl* fordParts = dynamic_cast<FordPartsImpl*>(parts);
customFordFixerFunction(fordCar, fordParts);
}
customFordFixerFunction(FordCar* fordCar, FordPartsImpl* fordParts){
fordCar->_carImpl->specialRepairMethod(fordParts);
}
};
Notice that I must use dynamic casting to access the technology-specific objects within the abstract interfaces. This is what makes me think I'm abusing inheritance and provoked me to ask this question originally.
Here is my ultimate goal:
UserInput userInput = getUserInput(); //just a configuration file ie XML/YAML
CarType carType = userInput.getCarType();
ICarParts* carParts = CarPartFactory::makeFrom(carType);
carParts->addPart(userInput);
ICarFeatures* carFeatures = CarFeaturesFactory::makeFrom(carType);
carFeatures->addFeature(userInput);
ICarMaker* carMaker = CarMakerFactory::makeFrom(carType);
ICar* car = carMaker->makeCar(carFeatures, carParts);
UserInput repairSpecs = getUserInput();
ICarParts* replacementParts = CarPartFactory::makeFrom(carType);
replacementParts->addPart(repairSpecs);
ICarFixer* carFixer = CarFixerFactory::makeFrom(carType);
carFixer->fixCar(car, replacementParts);
Perhaps now you all have a better understanding of what I'm trying to do and perhaps where I can improve.
I'm trying to use pointers of base classes to represent derived (ie Ford) classes, but the derived classes contain specific objects (ie FordPartsImpl) which are required by the other derived classes (ie FordCarFixer needs a FordCar and FordPartsImpl object). This requires me to use dynamic casting to downcast a pointer from the base to its respective derived class so I can access these specific Ford objects.
My question is: am I abusing inheritance here? I'm trying to have a many-to-many relationship between the workers and objects. I feel like I'm doing something wrong by having an Object family of class which literally do nothing but hold data and making the ObjectWorker class have to dynamic_cast the object to access the insides.
That is not abusing inheritance... This is abusing inheritance
class CSNode:public CNode, public IMvcSubject, public CBaseLink,
public CBaseVarObserver,public CBaseDataExchange, public CBaseVarOwner
Of which those who have a C prefix have huge implementations
Not only that... the Header is over 300 lines of declarations.
So no... you are not abusing inheritance right now.
But this class I just showed you is the product of erosion. I'm sure the Node as it began it was a shinning beacon of light and polymorphism, able to switch smartly between behavior and nodes.
Now it has become a Kraken, a Megamoth, Cthulu itself trying to chew my insides with only a vision of it.
Heed this free man, heed my counsel, beware of what your polymorphism may become.
Otherwise it is fine, a fine use of inheritance of something I suppose is an Architecture in diapers.
What other alternatives do I have if I want to only have a single work() method?
Single Work Method... You could try:
Policy Based Design, where a policy has the implementation of your model
A Function "work" that it is used by every single class
A Functor! Instantiated in every class that it will be used
But your inheritance seems right, a single method that everyone will be using.
One more thing....I'm just gonna leave this wiki link right here
Or maybe just copy paste the wiki C++ code... which is very similar to yours:
#include <iostream>
#include <string>
template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy
{
using OutputPolicy::print;
using LanguagePolicy::message;
public:
// Behaviour method
void run() const
{
// Two policy methods
print(message());
}
};
class OutputPolicyWriteToCout
{
protected:
template<typename MessageType>
void print(MessageType const &message) const
{
std::cout << message << std::endl;
}
};
class LanguagePolicyEnglish
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
class LanguagePolicyGerman
{
protected:
std::string message() const
{
return "Hallo Welt!";
}
};
int main()
{
/* Example 1 */
typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish> HelloWorldEnglish;
HelloWorldEnglish hello_world;
hello_world.run(); // prints "Hello, World!"
/* Example 2
* Does the same, but uses another language policy */
typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> HelloWorldGerman;
HelloWorldGerman hello_world2;
hello_world2.run(); // prints "Hallo Welt!"
}
More important questions are
How are you going to use an Int Object with your StringWorker?
You current implementation won't be able to handle that
With policies it is possible.
What are the possible objects?
Helps you define if you need this kind of behavior
And remember, don't kill a chicken with a shotgun
Maybe your model will never really change overtime.
You have committed a design error, but it is not "abuse of inheritance". Your error is that you are trying to be too generic. Meditate upon the principle of You Aren't Gonna Need It. Then, think about what you actually have. You don't have Objects, you have Dogs, Cats, and Horses. Or perhaps you have Squares, Polygons, and Lines. Or TextInEnglish and TextInArabic. Or ... the point is, you probably have a relatively small number of concrete things and they probably all go in the same superordinate category. Similarly, you do not have Workers. On the assumption that what you have is Dogs, Cats, and Horses, then you probably also have an Exerciser and a Groomer and a Veterinarian.
Think about your concrete problem in concrete terms. Implement only the classes and only the relationships that you actually need.
The point is that you're not accessing the specific functionality through the interfaces. The whole reason for using interfaces is that you want all Cars to be made, fixed and featured ... If you're not going to use them in that way, don't use interfaces (and inheritance) at all, but simply check at user input time which car was chosen and instantiate the correct specialized objects.
I've changed your code a bit so that only at "car making" time there will be an upward dynamic_cast. I would have to know all the things you want to do exactly to create interfaces I would be really happy with.
class ICar {
public:
ICar(void) {}
virtual ~ICar(void) {}
virtual void specialFeatureMethod(ICarFeatures *specialFeatures);
virtual void specialPartsMethod(ICarParts *specialParts);
virtual void specialRepairMethod(ICarParts *specialParts);
};
class FordCar : public ICar {
public:
FordCar(void) {}
~FordCar(void) {}
void specialFeatureMethod(ICarFeatures *specialFeatures) {
//Access the specialFeatures through the interface
//Do your specific Ford stuff
}
void specialPartsMethod(ICarParts *specialParts) {
//Access the specialParts through the interface
//Do your specific Ford stuff
}
void specialRepairMethod(ICarParts *specialParts) {
//Access the specialParts through the interface
//Do your specific Ford stuff
}
};
class ICarFeatures {
public:
ICarFeatures(void) {}
virtual ~ICarFeatures(void) {}
virtual void addFeature(UserInput feature) = 0;
};
class FordCarFeatures : public ICarFeatures{
public:
FordCarFeatures(void) {}
~FordCarFeatures(void) {}
void addFeature(UserInput feature){
//extract useful information out of feature, ie:
std::string name = feature.name;
int value = feature.value;
_fordFeature->specialAddFeatureMethod(name, value);
}
FordFeatureImpl* _fordFeature;
};
class ICarParts {
public:
ICarParts(void) {}
virtual ~ICarParts(void) {}
virtual void addPart(UserInput part) = 0;
};
class FordCarParts :public ICarParts{
public:
FordCarParts(void) {}
~FordCarParts(void) {}
void addPart(UserInput part) {
//extract useful information out of part, ie:
std::string name = part.name;
std::string dimensions = part.dimensions;
_fordParts->specialAddPartMethod(name, dimensions);
}
FordPartsImpl* _fordParts;
};
class ICarMaker {
public:
ICarMaker(void) {}
virtual ~ICarMaker(void) {}
virtual ICar* makeCar(ICarFeatures* features, ICarParts* parts) = 0;
};
class FordCarMaker {
public:
FordCarMaker(void) {}
~FordCarMaker(void) {}
ICar* makeCar(ICarFeatures* features, ICarParts* parts){
return customFordMakerFunction(features, parts);
}
ICar* customFordMakerFunction(ICarFeatures* features, ICarParts* parts) {
FordCar* fordCar = new FordCar;
fordCar->specialFeatureMethod(features);
fordCar->specialPartsMethod(parts);
return dynamic_cast<ICar*>(fordCar);
}
};
class ICarFixer {
public:
ICarFixer(void) {}
virtual ~ICarFixer(void) {}
virtual void fixCar(ICar* car, ICarParts* parts) = 0;
};
class FordCarFixer {
public:
FordCarFixer(void) {}
~FordCarFixer(void) {}
void fixCar(ICar* car, ICarParts* parts) {
customFordFixerFunction(car, parts);
}
void customFordFixerFunction(ICar* fordCar, ICarParts *fordParts){
fordCar->specialRepairMethod(fordParts);
}
};
One can do better (for certain values of "better"), with increased complexity.
What is actually being done here? Let's look point by point:
There's some object type, unknown statically, determined at run time from a string
There's some worker type, also unknown statically, determined at run time from another string
Hopefully the object type and the worker type will match
We can try to turn "hopefully" into "certainly" with some template code.
ObjectWorkerDispatcher* owd =
myDispatcherFactory->create("someWorker", "someObject");
owd->dispatch();
Obviously both object and worker are hidden in the dispatcher, which is completely generic:
class ObjectWorkerDispatcher {
ObjectWorkerDispatcher(string objectType, string workerType) { ... }
virtual void dispatch() = 0;
}
template <typename ObjectType>
class ConcreteObjectWorkerDispatcher : public ObjectWorkerDispatcher {
void dispatch () {
ObjectFactory<ObjectType>* of = findObjectFactory(objectTypeString);
WorkerFactory<ObjectType>* wf = findWorkerFactory(workerTypeString);
ObjectType* obj = of->create();
Worker<ObjectType>* wrk = wf->create();
wrk->doWork(obj);
}
map<string, ObjectFactory<ObjectType>*> objectFactories;
map<string, WorkerFactory<ObjectType>*> workerFactories;
ObjectFactory<ObjectType>* findObjectFactory(string) { .. use map }
WorkerFactory<ObjectType>* findWorkerFactory(string) { .. use map }
}
We have different unrelated types of Object. No common Object class, but we can have e.g. several subtypes of StringObject, all compatible with all kinds of StringWorker.
We have an abstract Worker<ObjectType> class template and concrete MyStringWorker : public Worker<StringObject> , OtherStringWorker : public Worker<StringObject> ... classes.
Both kinds of factories are inheritance-free. Different types of factories are kept completely separate (in different dispatchers) and never mix.
There's still some amount of blanks to fill in, but hopefully it all should be more or less clear.
No casts are used in making of this design. You decide whether this property alone is worth such an increase in complexity.
I think you have the right solution per your needs. One thing I see that can be improved is removing the use of carType from the function that deals with the objects at the base class level.
ICar* FordCarFixer::getFixedCar(UserInput& userInput)
{
FordCarParts* carParts = new FordPartFactory;
carParts->addPart(userInput);
FordCarFeatures* carFeatures = new FordCarFeatures;
carFeatures->addFeature(userInput);
FordCarMaker* carMaker = new FordCarMaker;
FordCar* car = carMaker->makeCar(carFeatures, carParts);
UserInput repairSpecs = getUserInput();
ForCarParts* replacementParts = new ForCarParts;
replacementParts->addPart(repairSpecs);
FordCarFixer* carFixer = new FordCarFixer;
carFixer->fixCar(car, replacementParts);
return car;
}
UserInput userInput = getUserInput();
ICar* car = CarFixerFactory::getFixedCar(userInput);
With this approach, most of the objects at FordCarFixer level are Ford-specific.
I would like to know how would you address such a problem:
I have a class Foo:
class Foo
{
public:
Foo() { }
~Foo() { }
float member1() { return _member1; }
private:
float _member1;
// other members etc...
}
A container class that, among other things, holds a container of pointers to Foo instances
class FooContainer
{
public:
FooContainer() { }
~FooContainer() { }
void addFoo(Foo* f) {_foos.push_back(f);}
private:
boost::ptr_vector<Foo> _foos;
}
My problem is this: at runtime I am required to "add" new (completely different) members to Foo, depending on the instructions from the GUI. I could address the problem by creating two "decorators" like this:
class Decorator1
{
public:
int alpha() { return _alpha; }
float beta() { return _beta; }
private:
int _alpha;
float _beta;
}
class Decorator2
{
typedef std::complex<float> cmplx;
public:
cmplx gamma() { return _gamma; }
double delta() { return _delta; }
private:
cmplx _gamma;
double _delta;
}
and then I would create two different Foo implementations:
class Foo1 : public Foo, public Decorator1
{ }
class Foo2 : public Foo, public Decorator2
{ }
and use each one according to the GUI command. However such a change would propagate through all my code and would force me to create two different versions for each class that uses Foo1 and Foo2 (e.g. I'd have to create FooContainer1 and FooContainer2).
A less intrusive way of doing this would be to create
class Bar: public Foo, public Decorator1, public Decorator2
{ }
and use this instead of Foo. In this case I'd call only the functions I need from Decorator1 and Decorator2 and ignore the others, but this seems to go against good OOP techniques.
Any suggestions regarding the problem ?
Why don't you use simple polymorphism like this?
class Foo
{
public:
Foo() { }
virtual ~Foo() { }
float member1() { return _member1; }
private:
float _member1;
// other members etc...
}
class Foo1 : public Foo
{
public:
int alpha() { return _alpha; }
float beta() { return _beta; }
private:
int _alpha;
float _beta;
}
class Foo2 : public Foo
{
typedef std::complex<float> cmplx;
public:
cmplx gamma() { return _gamma; }
double delta() { return _delta; }
private:
cmplx _gamma;
double _delta;
}
class FooContainer
{
public:
FooContainer() { }
~FooContainer() { }
void addFoo(Foo* f) {_foos.push_back(f);}
private:
boost::ptr_vector<Foo> _foos;
}
Then the client code need not change. According to the GUI command you can create Foo1 or Foo2 and add it to the single container. If necessary, you can use the dynamic_cast on Foo pointer to cast to Foo1 or Foo2. But, if you have written the client code properly, then this wouldn't be needed.
It sounds like you're looking to handle mixin-type functionality. To do that, you could use templates. This isn't run time in the sense that copies of each class will be generated, but it does save you the typing.
So for each decorator, do something like:
template<class TBase> class Decorator1 : public TBase
{
public:
void NewMethod();
}
Then you can, for example:
Foo* d = new Decorator1<Foo1>(...);
Of course, the only way to make this work at runtime is to decide which type you're going to create. However, you still end up with the type Foo, Foo1 and Decorator1 so you can cast between them/use RTTI as you need to.
For more on this, see this article and this document
Although I've suggested it as a potential solution, I personally would be tempted to go with the polymorphism suggestion if at all possible - I think that makes for better, easier to maintain code because parts of class implementations aren't scattered all over the place using mixins. Just my two cents - if you think it works, go for it.
the fundamental concept of a class is that it's encapsulated and hence that one cannot add members after the definition (though you can use polymorphism and create derived classes with additional members, but they cannot be called through pointer of the original class: you must cast them to derived which is dangerous), in particular not at run time.
So it seems to me you're requirement breaks the essential idea of OO programming. This suggests a simple solution: use non-member functions. They can be defined at any time, even run time (when you would also need to compile them). The overhead of the function pointer is the same as before (when you would need a pointer to a new member function).
How about policy based templates? Have a template class Foo that takes a class as a template parameter. Then, have two methods that call the decorator methods:
tempate <class Decor>
class Foo
{
public:
Foo() : { __d = Decor() }
~Foo() { }
float member1() { return _member1; }
Decor::method1type decoratorMember1() { return __d.getValueMethod1();}
Decor::method2type decoratorMember2() { return __d.getValueMethod2();}
private:
float _member1;
Decor __d;
// other members etc...
}
Then, in your complex decorator:
class Decor1 {
typedef std::complex<float> method1type;
typedef double method2type;
public:
method1type getValueMethod1() {return _gamma}
method2type getValueMethod2() {return _delta}
private:
method1type _gamma;
method2type _delta;
}
Same for the other. This way, your Foo code can have anything added to it, even if it's already compiled. Just make a declarator class. And instead of instantiating Foo1, do this:
Foo<Decor1> f;