Reputation: 4025
Please don't mind about the syntax. I thought of making the post as brief as possible.
We have a class hierarchy as below.
// abstract class.
class BaseProd
// concrete classes.
class Prod1 : public BaseProd
class Prod2 : public BaseProd
class Prod3 : public BaseProd
Each class has 3 sub classes like, Prod1New, Prod1Cancel and Prod1Modify the same case for the other 2 classes. Now, since New, Cancel and Modify are the events, we can represent them using enum.
The problem is, each class has lot of methods that are very specific to each event. Eg.
getRec(); // has specific implementations for each event.
Let's say there is something like process method.
void Prod1::process()
{
getRec(); // Each derived class overrides the method.
getPayment();// Each derived class overrides the method.
}
This way, we have 13 classes for 3 products having 3 events each.
If we have 2 more products the classes would grow by 8.
Can we have any alternate approach to this hierarchy?
UPDATE: The suggestion made by Tyler works only when Prod1's NewEvent and Prod2's NewEvent have the same implementation. Right? But in this case it is not. Atleast for some of the methods it is not.
Upvotes: 3
Views: 314
Reputation: 4415
Take a look at the Strategy Pattern. Make a strategy class for each event and inject it into the Prod class at runtime.
class BaseProd
{
public BaseProd(EventStrategy event) : _event(event);
private EventStrategy _event;
virtual public void Process();
}
void Prod1::process()
{
_event.getRec(); // Each derived class overrides the method.
_event.getPayment();// Each derived class overrides the method.
}
Now you can subclass EventStrategy and overrode getRec(), getPayment(), etc. And of course override process() too.
Upvotes: 2
Reputation: 76660
I don't see why the New, Cancel, and Modify messages should be subclasses of the products that they apply to. This doesn't satisfy the "is-a" relationship that should define inheritance. If class D
inherits from class B
, the statement "Every D
is a B
" should make sense and always be true. "A Prod1
is a BaseProd
" (i.e. "Every specific product is a product") -- that is true and makes sense.
But in the case of events, a Prod1Cancel
is not a Prod1
. It doesn't make sense to say "Every product1 cancellation event is a product1." Rather, a Prod1Cancel
is an event relating to Prod1
, so it makes more sense that the Prod1Cancel
class should contain a Prod1
object, rather than inheriting from it.
Since all of your products inherit from a BaseProd
class, you should really only need one class for each event, and not one class per event per product type, if you define your event classes like this:
class NewProductEvent {
public:
explicit NewProductEvent(BaseProd* product)
: m_product(product)
{ /* ... */ }
void getRec() { /* ... */ }
void getPayment() { /* ... */ }
private:
BaseProd* m_product; // Use this to access the data that the event
// needs from the product
};
Then, inside your Prod1::process()
method, you could generate a NewProductEvent
event for the current object, and call the appropriate methods on it:
void Prod1::process()
{
NewProductEvent event(this);
event.getRec();
event.getPayment();
}
Upvotes: 3