Lately I've been using some pattern quite a lot but I don't know if it is really good or not.
It goes as follows:
I have a set of function, lets call them ActionFoo, ActionBar and ActionZapper. These might differ in implementation but generally are used for same things across these. They may or may not be used together in a sequence(i.e. some of them can be used as a standalone), but there are some cases when they are, indeed grouped.
If I DO want to use them in a sequence I generally have two options:
1) write them manually each time
2) create a class hierarchy:
Approach #1:
void SomeActionSequence1()
{
ActionFoo1(1);
ActionBar1("Moo");
ActionZapper1("Moo", 42);
}
void SomeActionSequence2()
{
ActionFoo4(1);
ActionBar2("Moo");
ActionZapper1("Moo", 42);
}
This has drawbacks:
1) I won't have an ability to store state and will have to pass a lot of parameters to these Actions
2) I won't really have a coherent interface and won't be able to easily use autocompletion
Approach #2
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void ActionFoo(int) = 0;
virtual void ActionBar(string) = 0;
virtual void ActionZapper(string, int) = 0;
void ExecuteActionSequence();
};
void Base::ExecuteActionSequence()
{
ActionFoo(1);
ActionBar("Moo");
ActionZapper("Moo", 42);
}
Derived1 : public Base
{
void ActionFoo(int){/*some inplementation*/};
void ActionBar(string){/*some inplementation*/};
void ActionZapper(string, int){/*some inplementation*/};
}
Derived2 : public Base
{
void ActionFoo(int){/*some inplementation*/};
void ActionBar(string){/*some inplementation*/};
void ActionZapper(string, int){/*some inplementation*/};
}
and use it kinda like this:
Base* actionSequence = new Derived1();
actionSequence->ExecuteActionSequence();
Correct virtuals will be used and all seems ok except 2 small things:
1) Extensibility - I will have to write a class for each complex action
2) More importantly - either a lot of functions will be duplicated between these classes or
I will have a hierarchical tree too complex on my hands
I kinda "circumvent" problems of both approaches with "Interface Object" pattern (note, the name is mine, maybe it has a proper one)
What I do is this:
class InterfaceClass
{
public:
InterfaceClass(){};
~InterfaceClass(){};
void ActionFoo(int i)
{
if(fooPlaceholder != 0)
fooPlaceholder(i);
}
void ActionBar(string str)
{
if(barPlaceholder != 0)
barPlaceholder(str);
}
void ActionZapper(string str, int i)
{
if(zapperPlaceholder != 0)
zapperPlaceholder(str, i);
};
void ExecuteActionSequence();
std::function<void(int)> fooPlaceholder;
std::function<void(string)> barPlaceholder;
std::function<void(string, int)> zapperPlaceholder;
};
void InterfaceClass::ExecuteActionSequence()
{
ActionFoo(1);
ActionBar("Moo");
ActionZapper("Moo", 42);
}
in my application I do:
InterfaceClass complexAction;
complexAction.fooPlaceholder = ActionFoo;
complexAction.barPlaceholder = ActionBar;
complexAction.zapperPlaceholder = ActionZapper;
complexAction.ExecuteActionSequence();
Note that ActionFoo, ActionBar and ActionZapper are free functions, but at the same time I am using them in an interface. Also - I can easily switch between implementations of these functions, even at runtime(If I need this).
The advantage of this approach is - there is no need to create separate class structures for new actions and there is no code duplication of Action* functions.
Also - all functions can be brought to scope only where the complexAction is initialized.
The disadvantages are, I think, that it is not obvious just which Action* function is being used in the InterfaceClass object. Also - there is no ability to dynamic_cast such a class to determine just what it is.
I highly suspect that these are not only disadvantages of such approach so I would like comments about that.
It sounds like you want the Chain of Responsibility pattern
abstract class Action {
Action child;
Action(Action child) { this.child = child; }
Action() { }
void doAction(StateContext context);
void execute(StateContext context) {
if (child) child.execute(context);
doAction(context);
}
}
class ZapAction extends Action {
ZapAction(String theString, int theValue, Action child) { ... }
void doAction(Context context) { context.setZap(theString); }
}
Action actionSequenceAlpha = new ZapAction("", 1, new FooAction());
Action actionSequenceBeta = new FooAction(new BarAction(new ZapAction));
Advantages - Don't need to change this base object with a fixed set of strategies when you add a new Action, you can map actions in all sorts of fun and exciting ways, each object has a single responsibility and it is a nice standard pattern so everyone knows what is going on.
The other option would be to separate the sequence from the Action. Have an Action interface with the three Actions inheriting it. Then have a Sequence class with an execute method and a List of Actions
class Action { }
class FooAction extends Action { }
class Sequence {
List<Action> actions;
void execute() {
foreach (action : actions) action.execute();
}
}
Related
Consider I have a Plant class that has derived Fruit and Vegetable classes, and Fruit class has some more derived classes, like Orange and Apple, while Vegetable has derived Potato and Tomato. Assume, Plant has Plant::onConsume()=0; method:
class Plant
{
public:
virtual void onConsume(void)=0;
};
class Fruit:public Plant
{
};
class Orange:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Apple:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Vegetable:public Plant
{
};
class Potato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Tomato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Consumer
{
public:
void consume(Plant &p)
{
p.onConsume();
// Specific actions depending on actual p type here
// like send REST command to the remote host for Orange
// or draw a red square on the screen for Tomato
}
};
Suppose, I have a Consumer class with Consumer::consume(Plant) method. This "consume" method should perform different actions for different "Plants" instances/types, among calling Plant::onConsume() for any of "Plants". These action ain't directly related to the Plant class, require a lot of different additional actions and parameters, could literally be completely arbitrary, so cannot be implemented inside onConsume method.
What is the preferred method to implement this? As I understand, it is possible to implement some "Plant::getPlantType()=0" method, that would return plant type, but in this case I'm not sure what should it return. In case the returned value would be an enum, I'd need to change this enum each time I add a new derived class. And in any case, there's no control that multiple derived classes could return the same value.
Also, I'm aware there's a dynamic_cast conversion that returns nullptr if conversion could not be made, and typeid() operator that returns std::typeinfo (even with typeinfo::name()), which could be used in the switch() (it's just great for my case). But I'm afraid it could significally slow down the execution and make code heavier.
So, my question is, what is the preferred way in C++ to do that? maybe I just forgot about some simpler way to implement that?
A little update. Thank you for your explanations about inheritance, encapsulation etc! I supposed it's clear from my question, but it is not, I am sorry about that. So, please think about it, like I don't have an access to the whole Plant sources hierarchy, just need to implement this Consumer::onConsume(Plant). So I cannot add new specific methods in it. Or, also, it could be considered as a Plants library, that I have to write once, and make it usable for other devs. So, I could divide use cases/functionality into two parts: one that implemented "per class" in the Plant::onConsume() method, and second that is unknown yet and will differ depending on usage.
One option would be the visitor pattern, but this requires one function per type in some class. Basically you create a base class PlantVisitor with one Visit function per object type and pass add a virtual method to Plant that receives a PlantVisitor object and calls the corresponding function of the visitor passing itself as parameter:
class PlantVisitor
{
public:
virtual void Visit(Orange& orange) = 0;
virtual void Visit(Tomato& tomato) = 0;
...
};
class Plant
{
public:
virtual void Accept(PlantVisitor& visitor) = 0;
};
class Orange : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
class Tomato : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
This would allow you to do something like this:
class TypePrintVisitor : public PlantVisitor
{
public:
void Visit(Orange& orange) override
{
std::cout << "Orange\n";
}
void Visit(Tomato& tomato) override
{
std::cout << "Tomato\n";
}
};
std::vector<std::unique_ptr<Plant>> plants;
plants.emplace_back(std::make_unique<Orange>());
plants.emplace_back(std::make_unique<Tomato>());
TypePrintVisitor visitor;
for (size_t i = 0; i != plants.size(); ++i)
{
std::cout << "plant " << (i+1) << " is a ";
plants[i]->Accept(visitor);
}
Not sure the need for this does not indicate a design inefficiency though.
Btw: If you've got multiple visitors and do not necessarily want to implement logic for every single type in all of them, you could add default implementations in PlantVisitor that call the function for the supertype instead of specifying pure virtual functions.
Polymorphism is all about not having to know about a specific type. Usually your design is flawed if you discover having to detect a specific type explicitly.
At very first:
void Consumer::consume(Plant p)
does not work as intended! The Plant object is accepted by value, i. e. its bytes are copied one by one; however, only those of the Plant type, any others (those of derived types) are ignored and get lost within consume function – this is called object slicing.
Polymorphism only works with references or pointers.
Now assume you want to do something like the following (incomplete code!):
void Consumer::consume(Plant& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
if(/* p is apple */)
{
appleSpecific();
}
else if(/* p is orange */)
{
orangeSpecific();
}
generalCode2();
}
You don't want to decide yourself upon type, you let the Plant class do the stuff for you, which means you extend its interface appropriately:
class Plant
{
public:
virtual void onConsume() = 0;
virtual void specific() = 0;
};
The code of the consume function will now be changed to:
void Consumer::consume(Plant const& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
p.specific();
generalCode2();
}
You'll do so at any place you need specific behaviour (and specific is just a demo name, chose one that describes nicely what the function actually is intended to do).
p.onConsume();
generalCode1();
p.specific1();
generalCode2();
p.specific2();
generalCode3();
p.specific3();
generalCode4();
// ...
Of course you need now to provide appropriate implementations in your derived classes:
class Orange:public Fruit
{
void onConsume() override
{ }
void specific() override
{
orangeSpecific();
}
};
class Apple:public Fruit
{
void onConsume() override
{ }
void specific() override
{
appleSpecific();
}
};
Note the addition of override keyword, which protects you from accidentally creating overloaded functions instead actually overwriting in case of signature mismatch. It helps you, too, to locate all places of necessary changes if you discover having to change the function signature in the base class.
I am working on translating some Java code to C++.
In Java, we can create object from anonymous class, using existing constructor, and overriding some methods. E.g.,
class X {
public X(int value) {...}
public void work() {....}
}
void main(String[] args) {
X entity = new X(5) {
public void work() { /* Something else */ }
};
}
In C++, I know I can create anonymous class as following:
class X {
public:
virtual void work() {...}
}
class : public X {
public:
void work() {....}
} obj;
But C++ does not allow constructor in anonymous class, and it does not allow extending from object (e.g., the new X(5) { public void work() {} } like what Java allows.
How can I write similar code in C++?
Update 03/07/2020 05:27 CDT
More context about the problem I am working on. I am implementing aggregation function of a in-memory SQL database, and use the following class to represent an aggregation field:
class AggField {
public:
AggField(int colIndex);
virtual void reduce(DataRow&) = 0;
virtual double output() = 0;
}
For each type of aggregation, e.g., avg, min/max and sum, I have a subclass. For example
class Avg : public AggField {
private:
int counter_;
double value_;
public:
Avg(int colIndex) : AggField(colIndex), counter_(0), value_(0) {};
void reduce(DataRow&) override {
value_ += row[colIndex].doubleval();
counter_ += 1;
}
double output() override {
return value_ / counter_;
}
}
class Sum : public AggField {
.....
}
When processing a table, I will write the following
Table table = ...
auto agg_opr = Agg({
new Sum(0),
new Avg(1)
});
agg_opr.agg(table);
which does a sum on column 0, and average on column 1.
Sometimes(rare) I need to process more than one input columns. For example, doing a sum of col1 * (1 + col2). Instead of creating a new subclass of AggField, I would like to write something similar to:
Table table = ...
auto agg_opr = Agg({
new Sum(0) {
void reduce(DataRow& row) {
value_ += row[0].doubleval() * (1 + row[1].doubleval());
}
},
new Avg(1),
new Max(1)
});
agg_opr.agg(table);
I can't say that I know how to write idiomatic Java but I'm guessing that this pattern in Java is an alternative to lambdas in C++. I remember using an anonymous class long ago when I was working with Swing. I think I did something like this:
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// ...
}
});
This is sugar for inheriting from a class and overriding a method. Doing precisely that is not really how I would like to attach an event listener in C++. I'd prefer to do this:
button.addMouseClickListener([](const MouseEvent &e) {
// ...
});
In the case of an event listener, the closure would need to be stored in a std::function or something similar. This has roughly the same performance as a virtual call.
I don't really know much about where you're using this class but if you need to store it aside (like an event listener or something) then declaring the class the long way or using std::function are probably the cleanest options. If you don't need to store it aside (like a policy for an algorithm) then you could use a functor. Of course, you can store aside a functor but it takes a bit of template machinery and probably isn't worth it (although it does have more flexibility).
struct MyPolicy {
int doSomething(int i) {
return i * 3;
}
double getSomething() const {
return d;
}
double d;
};
template <typename Policy>
void algorithm(Policy policy) {
// use policy.doSomething and policy.getSomething...
}
Using a functor or lambda with a template has much better performance than using virtual functions. In the above example, the compiler can and probably will inline the calls to doSomething and getSomething. This isn't possible with virtual functions.
If I knew more about the real problem that you're trying to solve then I might be able to write a more specific and helpful answer.
After seeing the updated question I have another suggestion. That would be to create a subclass for custom aggregate functions. Of course, this has plenty of limitations.
template <typename Func>
class CustomAgg : public AggField {
public:
CustomAgg(int colIndex, Func func)
: AggField{colIndex}, func{func} {}
void reduce(DataRow &row) override {
func(value, row);
}
double output() override {
return value;
}
private:
Func func;
double value = 0.0;
// could add a `count` member if you want
};
auto agg_opr = Agg({
new CustomAgg{0, [](double &value, DataRow &row) {
value += row[0].doubleval() * (1 + row[1].doubleval());
}},
new Avg(1),
new Max(1)
});
Honestly, I think the best solution for you is to not try to implement a Java feature in C++. I mean, if you need to handle multiple columns in some specific operation then create a class just for that. Don't take any shortcuts. Give it a name even though you might only use it in one place.
C++ has anonymous namespaces, which effectively lets you create classes that are completely isolated to the translation units they're declared in:
namespace {
class X {
public:
X(int) { /* ... */ } // Ok to have a constructor
void work();
};
}
int main(int argc, char **argv)
{
X entity{5};
// ...
}
Now, you have to declare them in global scope, you can't declare them in inner scope. You'll also need to give these classes normal names that you can reference them by in the same translation unit; but for all practical purposes they're completely anonymous and inaccessible from other translation units. Another translation unit can declare its own anonymous class "X", and there won't be any conflicts.
You can use anonymous classes in all other normal ways, subclass them, etc... You can create an anonymous class that's a subclass of a regular, non-anonymous class, which gets you pretty close to what Java does, here.
Some compilers also offer extensions where you can declare classes in inner scopes, and they'll also work very similar to anonymous namespaces, but that's going to be a compiler-specific extension.
Let's say I have a parent class, Arbitrary, and two child classes, Foo and Bar. I'm trying to implement a function to insert any Arbitrary object into a database, however, since the child classes contain data specific to those classes, I need to perform slightly different operations depending on the type.
Coming into C++ from Java/C#, my first instinct was to have a function that takes the parent as the parameter use something like instanceof and some if statements to handle child-class-specific behavior.
Pseudocode:
void someClass(Arbitrary obj){
obj.doSomething(); //a member function from the parent class
//more operations based on parent class
if(obj instanceof Foo){
//do Foo specific stuff
}
if(obj instanceof Bar){
//do Bar specific stuff
}
}
However, after looking into how to implement this in C++, the general consensus seemed to be that this is poor design.
If you have to use instanceof, there is, in most cases, something wrong with your design. – mslot
I considered the possibility of overloading the function with each type, but that would seemingly lead to code duplication. And, I would still end up needing to handle the child-specific behavior in the parent class, so that wouldn't solve the problem anyway.
So, my question is, what's the better way of performing operations that where all parent and child classes should be accepted as input, but in which behavior is dictated by the object type?
First, you want to take your Arbitrary by pointer or reference, otherwise you will slice off the derived class. Next, sounds like a case of a virtual method.
void someClass(Arbitrary* obj) {
obj->insertIntoDB();
}
where:
class Arbitrary {
public:
virtual ~Arbitrary();
virtual void insertIntoDB() = 0;
};
So that the subclasses can provide specific overrides:
class Foo : public Arbitrary {
public:
void insertIntoDB() override
// ^^^ if C++11
{
// do Foo-specific insertion here
}
};
Now there might be some common functionality in this insertion between Foo and Bar... so you should put that as a protected method in Arbitrary. protected so that both Foo and Bar have access to it but someClass() doesn't.
In my opinion, if at any place you need to write
if( is_instance_of(Derived1) )
//do something
else if ( is_instance_of(Derived2) )
//do somthing else
...
then it's as sign of bad design. First and most straight forward issue is that of "Maintainence". You have to take care in case further derivation happens. However, sometimes it's necessary. for e.g if your all classes are part of some library. In other cases you should avoid this coding as far as possible.
Most often you can remove the need to check for specific instance by introducing some new classes in the hierarchy. For e.g :-
class BankAccount {};
class SavingAccount : public BankAccount { void creditInterest(); };
class CheckingAccount : public BankAccount { void creditInterest(): };
In this case, there seems to be a need for if/else statement to check for actual object as there is no corresponsing creditInterest() in BanAccount class. However, indroducing a new class could obviate the need for that checking.
class BankAccount {};
class InterestBearingAccount : public BankAccount { void creditInterest(): } {};
class SavingAccount : public InterestBearingAccount { void creditInterest(): };
class CheckingAccount : public InterestBearingAccount { void creditInterest(): };
The issue here is that this will arguably violate SOLID design principles, given that any extension in the number of mapped classes would require new branches in the if statement, otherwise the existing dispatch method will fail (it won't work with any subclass, just those it knows about).
What you are describing looks well suited to inheritance polymorphicism - each of Arbitrary (base), Foo and Bar can take on the concerns of its own fields.
There is likely to be some common database plumbing which can be DRY'd up the base method.
class Arbitrary { // Your base class
protected:
virtual void mapFields(DbCommand& dbCommand) {
// Map the base fields here
}
public:
void saveToDatabase() { // External caller invokes this on any subclass
openConnection();
DbCommand& command = createDbCommand();
mapFields(command); // Polymorphic call
executeDbTransaction(command);
}
}
class Foo : public Arbitrary {
protected: // Hide implementation external parties
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Foo specific fields here
}
}
class Bar : public Arbitrary {
protected:
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Bar specific fields here
}
}
If the base class, Arbitrary itself cannot exist in isolation, it should also be marked as abstract.
As StuartLC pointed out, the current design violates the SOLID principles. However, both his answer and Barry's answer has strong coupling with the database, which I do not like (should Arbitrary really need to know about the database?). I would suggest that you make some additional abstraction, and make the database operations independent of the the data types.
One possible implementation may be like:
class Arbitrary {
public:
virtual std::string serialize();
static Arbitrary* deserialize();
};
Your database-related would be like (please notice that the parameter form Arbitrary obj is wrong and can truncate the object):
void someMethod(const Arbitrary& obj)
{
// ...
db.insert(obj.serialize());
}
You can retrieve the string from the database later and deserialize into a suitable object.
So, my question is, what's the better way of performing operations
that where all parent and child classes should be accepted as input,
but in which behavior is dictated by the object type?
You can use Visitor pattern.
#include <iostream>
using namespace std;
class Arbitrary;
class Foo;
class Bar;
class ArbitraryVisitor
{
public:
virtual void visitParent(Arbitrary& m) {};
virtual void visitFoo(Foo& vm) {};
virtual void visitBar(Bar& vm) {};
};
class Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Parent specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitParent(*this);
}
};
class Foo: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Foo specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitFoo(*this);
}
};
class Bar: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Bar specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitBar(*this);
}
};
class SetArbitaryVisitor : public ArbitraryVisitor
{
void visitParent(Arbitrary& vm)
{
vm.DoSomething();
}
void visitFoo(Foo& vm)
{
vm.DoSomething();
}
void visitBar(Bar& vm)
{
vm.DoSomething();
}
};
int main()
{
Arbitrary *arb = new Foo();
SetArbitaryVisitor scv;
arb->accept(scv);
}
In many cases in my application i need class A to register itself as a listener on class B to receive notification when something happens. In every case i define a separate interface B implements and A can call do. So for example, A will have the following method:
void registerSomeEventListener(SomeEventListener l);
Also, in many cases, B will need to support multiple listeners so i reimplement the registration and notifyAll logic.
One generic way i know is to have some EventListener (implement by A) and EventNotifier (implement by B) classes. In this case each event is identified by a string and A implements the method:
void eventNotified(string eventType);
I think this is not a good solution. It will result in many if-else statements in case A listens to several events and might result in bugs when event names are changed only in the listener or the notifier.
I wonder what is the correct way to implement the observer pattern in C++?
Take a look at boost::signals2. It provides a generic mechanism to define "signals" where other objects can register. The signal owner can then notify observers by "firing" the signal. Instead of register-methods, the subject defines signals as members which then keep track of connected observers and notify them when initiated. The signals are statically typed and accept every function with the matching signature. This has the advantage that there is no need for inheritance and thus a weaker coupling than the traditional observer inheritance hierarchy.
class Subject {
public:
void setData(int x) {
data_ = x;
dataChanged(x);
}
boost::signals2<void (int)> dataChanged;
private:
int data_;
};
class Observer {
public:
Observer(Subject& s) {
c_ = s.dataChanged.connect([&](int x) {this->processData(x);});
}
~Observer() {
c_.disconnect();
}
private:
void processData(int x) {
std::cout << "Updated: " << x << std::endl;
}
boost::signals2::connection c_;
};
int main() {
Subject s;
Observer o1(s);
Observer o2(s);
s.setData(42);
return 0;
}
In this example, the subject holds some int data and notifies all registered observers when the data is changed.
Lets say you have a generic event fireing object:
class base_invoke {
public:
virtual ~base_invoke () {};
virtual void Invoke() = 0;
}
But you want to fire events on different types of objects, so you derive from base:
template<class C>
class methodWrapper : public base_invoke {
public:
typedef void (C::*pfMethodWrapperArgs0)();
C * mInstance;
pfMethodWrapperArgs0 mMethod;
public:
methodWrapper(C * instance, pfMethodWrapperArgs0 meth)
: mInstance(instance)
{
mMethod = meth;
}
virtual void Invoke () {
(mInstance->*mMethod)();
}
}
Now if you create a wrapper for a collection of pointers to base_invoke you can call each fireing object and signal whichever method on whichever class you'd like.
You can also turn this collection class into a factory for the fireing objects. to simplyfy the work.
class Event {
protected:
Collection<base_invoke *> mObservers;
public:
// class method observers
template<class C>
void Add (C * classInstance, typename methodWrapper<C>::pfMethodWrapperArgs0 meth) {
methodWrapper<C> * mw = NEW(methodWrapper<C>)(classInstance, meth);
mObservers.Add(ObserverEntry(key, mw));
}
void Invoke () {
int count = mObservers.Count();
for (int i = 0; i < count; ++i) {
mObservers[i]->Invoke();
}
}
};
And your done with the hard work. Add an Event object anyplace you want listeners to subscribe. You'll probably want to expand this to allow removal of listeners, and perhaps to take a few function parameters but the core is pretty much the same.
I'm writing a piece of generic software that will be loaded on to many different variants of the same basic hardware. They all have the same processor, but with different peripherals and their own functions that need to be carried out. The software will know which variant it should run by reading a hardware switch value.
Here's my current implementation in a nutshell:
class MyBase
{
public:
MyBase() { }
virtual run() = 0;
}
class VariantA : public MyBase
{
public:
VariantA () { }
virtual run()
{
// Run code specific to hardware Variant-A
}
}
class VariantB : public MyBase
{
public:
VariantB () { }
virtual run()
{
// Run code specific to hardware Variant-B
}
}
void main()
{
MyBase* variant;
uint_8 switchValue = readSwitchValue();
switch(switchValue)
{
case 0:
variant = new VariantA();
break;
case 1:
variant = new VariantB();
break;
}
variant->run();
}
Now this works just fine. I read the hardware value and use a switch statement to create the new corresponding class.
The problem is that there are a lot of variants I have to deal with. Currently about 15, with the potential to add another 20-30 in the near future. I have really come to despise switch statements that run for hundreds of lines, so I'm really looking for a better way to do this, probably through templates.
I want to be able to use my hardware value to look up a type and use that type to create my new object. Ideally when I add a new variant, I create the new class, add that class type to my lookup table with it's matching hardware value, and it's good to go.
Is this possible at all? What's a good solution here?
As stated, you make a factory, but not necessarily with naive switch statements. What you can do is make a template class to create the relevant object and dynamically add these to your factory.
class VariantinatorBase {
public:
VariantinatorBase() {}
virtual ~VariantinatorBase() {}
virtual std::unique_ptr<Variant> Create() = 0;
};
template< class T >
class Variantinator : public VariantinatorBase {
public:
Variantinator() {}
virtual ~Variantinator() {}
virtual std::unique_ptr<Variant> Create() { return std::make_unique<T>(); }
};
Now you have a class factory that allows you to register these.
class VariantFactory
{
public:
VariantFactory()
{
// If you want, you can do all your Register() calls in here, and even
// make the Register() function private.
}
template< uint8_t type, typename T >
void Register()
{
Register( type, std::make_unique<Variantinator<T>>() );
}
std::unique_ptr<Variant> Create( uint8_t type )
{
TSwitchToVariant::iterator it = m_switchToVariant.find( type );
if( it == m_switchToVariant.end() ) return nullptr;
return it->second->Create();
}
private:
void Register( uint8_t type, std::unique_ptr<VariantinatorBase>&& creator )
{
m_switchToVariant[type] = std::move(creator);
}
typedef std::map<uint8_t, std::unique_ptr<VariantinatorBase> > TSwitchToVariant;
TSwitchToVariant m_switchToVariant;
};
At the beginning of your program, create the factory and register your types:
VariantFactory factory;
factory.Register<0, VariantA>();
factory.Register<1, VariantB>();
factory.Register<2, VariantC>();
Then later, you want to call on it:
std::unique_ptr<Variant> thing = factory.Create( switchValue );
You are looking for a factory
http://www.oodesign.com/factory-pattern.html
A factory is a software module (a method, a class) whose sole purpose is to create the right object for the job. An example using a factory class:
class VariantFactory
{
MyBase* CreateObject(uint_8 value);
}
And the CreateObject method can be filled out to give you the type of object that you need.
In the case of a very small selection of objects with simple construction, a simple switch statement might suffice. As soon as you get a lot of objects or ones that require more detailed construction, a factory is quite useful.
I made this a comment; let's turn it into an answer:
Personally, I think a "switch/case" block to create the appropriate class is probably an optimal solution. Just put your case statement in a static "factory" method that returns a reference to the specific class. IMHO...
Here's a good example: factory method design pattern
Class Book : public Product
{
};
class Computer : public Product
{
};
class ProductFactory
{
public:
virtual Product* Make(int type)
{
switch (type)
{
case 0:
return new Book();
case 1:
return new Computer();
[...]
}
}
}
Call it like this:
ProductFactory factory = ....;
Product* p1 = factory.Make(0); // p1 is a Book*
Product* p2 = factory.Make(1); // p2 is a Computer*
// remember to delete p1 and p2
Note that in his most excellent response, smink also suggests some other design alternatives, too.
BOTTOM LINE: There's nothing inherently "wrong" with a switch/case block. Even for a switch with many case options.
IMHO...
PS:
This really isn't creating a "dynamic type". Rather, it's "creating a static type dynamically". That would be equally true if you used a template or an enum solution as well. But again - I vastly prefer the "switch/case".
Update: I am leaving my original solution here for posterity, but consider the solution provided by paddy to be superior and less error prone. With only a couple of slight improvements I think it's actually about as good as you can possibly get.
Consider this design:
class VariantA : public MyBase
{
static MyBase *CreateMachineInstance() { return new VariantA; }
};
class VariantB : public MyBase
{
static MyBase *CreateMachineInstance() { return new VariantB; }
};
Now, all you need is an std::map that uses a uint_8 as the key and maps it to a function pointer (returning MyBase). Insert the identifiers in the map (pointing each to the appropriate machine creation function) and then read the code and just use the map to find what machine you're using.
This is loosely based on a concept/pattern called a "factory" but may break slightly if your machine constructors require different arguments or you need to perform additional per-machine initialization/operations - and from what you mention it sounds like you might.
If that's the case, you can still use this pattern but you will have to make some tweaks and rearchitect things a bit but you will end up with something much cleaner and easier to augment and maintain.
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
template<class T,class T1>
class HeroHonda
{
private:
T millage;
T1 *options;
public:
HeroHonda() {
puts("constructed");
options=new T1[20];
strcpy(options,"Good millage,Powerstart");
millage=110;
}
virtual T features() {
cout<<options<<"millage is"<<millage<<endl;
return 1;
}
// virtual T Extrafeatures() = 0;
~HeroHonda() {
cout<<"destructor"<<endl;
delete [] options;
}
};
int main()
{
HeroHonda <int,char> *Ptr=new HeroHonda <int,char>;
Ptr->features();
delete Ptr;
}