I have three objects; Action, Issue and Risk. These all contain a nunber of common variables/attributes (for example: Description, title, Due date, Raised by etc.) and some specific fields (risk has probability). The question is:
Should I create 3 separate
classes Action, Risk and Issue each
containing the repeat fields.
Create a parent class "Abstract_Item"
containing these fields and
operations on them and then have
Action, Risk and Issue subclass
Abstract_Item. This would adhere to
DRY principal.
My Perspective
Let's say, if you used inheritance. Over a period you have new attributes that are common to only Action and Issue but not Risk. How will you handle this? If you put them under parent then Risk is inheriting stuff that is irrelevant (Liskov Substituon Principle knocking?). If you put then in Action and Risk separately then you are breaking DRY, the initial reason why you started inheritance. Point is Inhertence for re-use is bad. If there is no "is-a" then better not use it and when you are in doubt then there is no real "is-a".
My Preference
There are other ways of achieving DRY as shown in below example code. With this addition of new properties my be another Common2, addition of new behavior is new CommonBehavior2 if they are not applicable to all 3 classes; if they are then just change existing Common and CommonBehavior
public class Common implements CommonBehavior
{
String Description;
String title;
public void f() {}
}
public interface CommonBehavior
{
void f();
}
public class Action implements CommonBehavior
{
private Common delegate;
public void f()
{
delegate.f();
}
}
Also look at my answer to a similar question with another practical example Design pattern to add a new class
Yes, adhering to DRY is usually a very good idea except if the classes have very, very different uses (i.e. both apples and cars may be red, still I wouldn't derive both of them from a base class called ProbablyRed
). In your case, however, I'd definitely go for a base class since the implementations you describe (Action
, Issue
, Risk
) all seem to be some kind of business rule with very similar semantics.
You seem to be answering this yourself. As you say, DRY.
The abstract parent class sounds like the way to go. It will also make it possible or easier (depending on your language) to implement and use functions which act on any of the three items. For example, you could have a "Get a list of all items raised by {user}" function.
Another facet may become visible if you look at the use cases, probably dealing with different subgroups of the properties.
If for example "label", "due date" and "raised" are used in a todo like application and other properties of "Action" and "Risk" will be prevalent when working on that task, you might consider an aggregation of lets say Task (label, due date,...) and Topic which is a polymorphic reference to things like Action, Issue or whatever will come up someday
I guess I have answered the same question here
When to create a class vs setting a boolean flag?
Don't subclass just because objects share some data or operations. Consider composition as the default way to follow DRY.
In your particular case, only create a parent class if your objects are actually related, i.e. there's a semantic "is a" relationship to the parent class. For example, if Action, Issue, and Risk are all Ticket objects.