PDA

View Full Version : Is this possible?



Atomic_Sheep
24th August 2013, 17:58
Hi Guys,

Say I have a function with just a single parameter. Is it possible to call a particular object based on that param? i.e. I have 2 different classes ClassA and ClassB. If param = 1, I call ClassA.doSomething if param = 2, i call ClassB.doSomething. Note, that both the classes have the same function name but each one does this same taskdifferently and achieves a different result.

The only solution I can think of would use cases or if and else:


Function(iParam)
{
if(iParam == 1)
{
ClassA.doSomething;
}
else if(iParam ==2)
{
ClassB.doSomething;
}
}

I obviously want to steer away from having 100 if and else statements. The main problem I have with this is the fact that I'll be creating an instance on the heap of only 1 of these classes, and I just need to access an objects function based on which one is loaded on the heap.

wysota
25th August 2013, 00:40
e.g.


class SomethingIface {
public:
virtual ~SomethingIface() {}
virtual void doSomething() = 0;
virtual bool canDoSomething(int param) const { return false; }
};

class SomethingA : public SomethingIface {
public:
// ...
void doSomething() { ... }
bool canDoSomething(int param) const { return param == 1; }
};

class SomethingB : public SomethingIface {
public:
// ...
void doSomething() { ... }
bool canDoSomething(int param) const { return param == 2; }
};

void Function(int param) {
QList<SomethingIface*> somethingIfaces = ... ;
bool canDoSomething = false;
foreach(SomethingIface *iface, somethingIfaces) {
if(iface->canDoSomething(param)) { iface->doSomething(); break; }
}
}


I obviously want to steer away from having 100 if and else statements. The main problem I have with this is the fact that I'll be creating an instance on the heap of only 1 of these classes, and I just need to access an objects function based on which one is loaded on the heap.
In such case you only need a common base class, without the need for a "canDoSomething" method.

Atomic_Sheep
25th August 2013, 08:55
Hmm, not quite the answer I was after but I think you've hit the spot regardless, pretty sure inheritance is what I'm looking for.

Except now I'm not sure whether a structure such as this will work:

class GLWidget
class Cat : GLWidget
class Dog : GLWidget

I then want to create a Cat object and have my GLScene built based off the fact that I'm trying to draw a cat. I'm essentially trying to get GLWidget to work backwards, my intuition tells me something is amiss here.

wysota
25th August 2013, 18:18
There is a number of design patterns you can use including Strategy, Builder or Factory.

Atomic_Sheep
27th August 2013, 09:56
Hmm interesting to see what sometimes you learn when you ask a seemingly stupid question, been looking for something like this for quite some time! Many thanks.

Atomic_Sheep
29th August 2013, 11:17
Well, I've decided that the right thing for me would be to use a strategy pattern, at least I think so. Question now is, I have a bunch of classes like apple, orange, banana and I'm going to use a strategy class such as fruit to get functionality for my program, only question that I'm not sure about is the interface and whether I'm doing everything right, because at the moment, it feels like I'm overlooking something but I'm not sure what.

So given my three classes of individual fruit and the strategy class of fruit, the only way that I can think of this all working would be to have the individual classes to provide unique functionality but have a common interface to the 'fruit' strategy class whereby let's say I have identical public functions visible to the fruit class of: pick, eat and throw away or something. The only thing that I'm not sure about is the whole idea of not having any copied code. Each piece of fruit will have unique functionality in each of these functions, however the fact that we have identical function names shared between each of the classes somehow feels wrong to me.

Then we get back to my original question of using a parameter to identify which class we need i.e. say in my 'fruit' strategy class, I have functions which figure out which fruit I need for a specific task e.g. a banana desert would require a banana, however I still need to invoke the same functions e.g.


Function(iParam)

{

if(iParam == 1)

{

Apple->Eat;

}

else if(iParam ==2)

{

Banana->Eat;

}

}

So I would imagine I'll need to look into function prototypes to be able to include this functionality?

More importantly, the thing I'm trying to figure out most of all are flaws in my logic. I've outlined how I'm going about solving my problem and am wondering whether there are any glaring errors that I'm making. As I said, something doesn't smell quite right to me, but I just don't know what, hopefully what I've outlined provides enough information to provide some sort of useful feedback.

wysota
29th August 2013, 11:52
I think you didn't understand the strategy pattern. The "strategy" is the "functionality", not the "object". Say you have a "Sort" strategy. You can then implement different sorting algorithms as subclasses of the Sort class that operate on a generic sortable object. Then you instantiate one of the algorithm objects so that if some part of your program wants to sort something, it takes the stored concrete strategy object and invoke it through the generic Sort interface. The strategy pattern aims to provide means to operate on objects without adding methods to classes of those objects. In your case you could have a "Peal" strategy that works on "Fruit" class and have two implementations (e.g. ManualPeal and MechanicPeal) that can peal any object implementing the Fruit class (be it Banana or Apple). The strategy should be agnostic to the type of fruit it peals, i.e. it should never care about the details of the fruit -- it is the responsibility of the Fruit class to provide all the needed functionality for the Peal strategy (e.g. though virtual methods reimplemented in particular Fruit subclasses).

Thus looking at your last snippet, your Fruit class should have a "eat" virtual method which is reimplemented by both Banana and Apple. Of course that is regardless of the use of the strategy pattern that does not look very fit for the functionality of your last snippet. If I were to force the pattern there, I would do something along the lines of:


function(iparam) {
FruitEater *eater = 0;
switch(iparam) {
case 1: eater = new AppleEater; break;
case 2: eater = new BananaEater; break;
// ...
}
if(!eater) return;
eater->Eat(object);
delete eater;
}

But a simpler equivalent if you don't care about the purity of the API is just:


function(fruit) {
fruit->eat();
}

The difference is that in the second case the Fruit class needs to have virtual methods and in the first case it doesn't as the virtual method is placed in the Eater class (and its subclasses).

Atomic_Sheep
30th August 2013, 12:03
Thanks for the clarifications, I understand what you're saying and it makes perfect sense, I'm having trouble figuring out how to make all my classes and functions in such a way that they work in the described fashion. Will keep working away it :), thanks for the info, another explanation is always helpful.

wysota
30th August 2013, 12:13
It would be extermely helpful if you stated what you were trying to achieve.

Atomic_Sheep
19th September 2013, 11:39
Deleted... I think I'm trying to solve an inheritance problem using composition... looking into it!

wysota
19th September 2013, 12:40
"Function" is just some entry point to the canDoSomething-doSomething functionality.

The main idea behind the approach is that objects themselves define conditions (like in your if blocks) that need to be satisfied for the code to run. If a condition (e.g. param==1) is satisfied, the object reports it and the manager executes functionality of the object. Otherwise it checks the next object until it finds one that can handle the condition.

Suppose you have two workers who can build houses -- one of them is a carpenter and can build houses from wood, the other is a mason who can build houses from bricks. If you have them both in your inventory then you can ask each of them "can you build a house from 'wood'?" and one of them will confirm and the other will deny. Then you know which one to choose without having to know their professions.