Search code examples
oopinheritanceumlclass-diagramclass-design

Is it possible for two child-classes to work together


I have one base-class named Product. Classes "Drink" and "Pizza" are subclasses that inherit from the "Product" class. I also have a class named "Ingredient" Which is a part of the Pizza class, so the Pizza class should have an instance (a list) of the Ingredient class.

My question is: Since the Ingredient has the same properties like all the other "Products", can it also inherit from the "Product" class while working together with the "Pizza" subclass?

Click here to see my current UML Design


Solution

  • Yes, they can!

    Yes, classes that inherit from the same super-class can perfectly work together. There is no incompatibility. There is even a design pattern that uses both relations on the same classes (the composite pattern).

    Remark: The wording "Working together" is somewhat ambiguous and could mean different things. But your class-diagram is precise enough and shows that you mean a possible association.

    But how?

    Your diagram shows a navigable association between Pizza and Ingredient (the open arrow). This means that the implementation shall make sure that a pizza can easily find its ingredients.

    In your narrative you mention a list. I understand that an Ingredient can exist without any Pizza, but a Pizza can have several Ingredient. It is important to specify this multiplicity on the diagram, by indicating * on the Ingredient side of the association.

    The relationship in the opposite direction has still some mysteries:

    • Navigability is unspecified: we don't know if an Ingredient shall be able to easily find the related pizza or if this is not relevant. You may specify this further with an arrow-head in the opposite direction (navigable) or with an X across the line (non-navigable). You have the right to leave this unspecified and decide later. The navigability has an impact on the way the classes can work together: it means that Pizza can "work with" ingredient (e.g. use it as parameter in an operation, invoke an ingredient operation directly, etc...). But the absence of navigability in the opposite direction would mean that Ingredient could not by itself initiate a collaboration with its pizza.
    • More important, the multiplicity: we do not know if an ingredient is associated only with one pizza (0..1), or if it can be shared between several (0..*). This is very important to know because the implementation would be very different (in the latter case you'd have a many-to-many association).

    Overgeneralization ?

    Inheritance is tempting when one discovers OOP. However, inheritance has a lot of implications, constraints and consequences. Therefore, use it wisely.

    A useful advice is to start considering that A inherits from B, only if A is a more specialized B, or conversely, that B is a more generalization of A. It is dangerous to use inheritance just because some properties or operations share the same name. Names can by the way be misleading.

    In your case, I understand a Product as something that the company sells at a given price: Drink, Pizza, maybe Antipasti or Pasta. The price indicated, is the price requested from the customer. I therefore wonder if an Ingredient is sold to the customer. AN ingredient may have a price, but it is a purchase price. A purchase price is different from a sales price: imagine that a restaurant would subcontract some very special pizza: the sales price would be different from the purchasing price.

    Of course, if your Product is something more general, in the business meaning, and if it can have a sales price and a purchase price, and is not necessarily on the menu, then no problem, go-ahead. But be aware that such generalized products are much more complex to manage (e.g. here a well-known ERP example with more than 20 different screens to manage all the aspects of a product).

    Other remarks

    A very common advice is to prefer composition over inheritance. This rule of thumb aims to remind us to think twice before we use inheritance. Let's be clear, in case of doubt: this does not mean that inheritance and composition are incompatible.