2

I know I might get downvoted for this, but I'm really curious.

I was taught that inheritance is a very powerful polymorphism tool, but I can't seem to use it well in real cases.

So far, I can only use inheritance when the base class is an abstract class.

Examples :

  1. If we're talking about Product and Inventory, I quickly assumed that a Product is an Inventory because a Product must be inventorized as well. But a problem occured when user wanted to sell their Inventory item. It just doesn't seem to be right to change an Inventory object to it's subtype (Product), it's almost like trying to convert a parent to it's child.

  2. Another case is Customer and Member. It is logical (at least for me) to think that a Member is a Customer with some more privileges. Same problem occurred when user wanted to upgrade an existing Customer to become a Member.

  3. A very trivial case is the Employee case. Where Manager, Clerk, etc can be derived from Employee. Still, the same upgrading issue.

I tried to use composition instead for some cases, but I really wanted to know if I'm missing something for inheritance solution here.

My composition solution for those cases :

  1. Create a reference of Inventory inside a Product. Here I'm making an assumption about that Product and Inventory is talking in a different context. While Product is in the context of sales (price, volume, discount, etc), Inventory is in the context of physical management (stock, movement, etc).

  2. Make a reference of Membership instead inside Customer class instead of previous inheritance solution. Therefor upgrading a Customer is only about instantiating the Customer's Membership property.

  3. This example is keep being taught in basic programming classes, but I think it's more proper to have those Manager, Clerk, etc derived from an abstract Role class and make it a property in Employee.

I found it difficult to find an example of a concrete class deriving from another concrete class.

Is there any inheritance solution in which I can solve those cases?

Being new in this OOP thing, I really really need a guidance.

Thanks!

6 Answers 6

11

The first thing that I'm going to suggest is that you take a few moments to read some of the other questions and answers on inheritance vs. composition that are here on Stack Exchange. There are several linked on the sidebar, for example.

I'll just address your first example:

Inventory shouldn't inherit from Product.(Are you selling an inventory? How do I take that home?)

Neither should Product inherit from Inventory. How is a salable item, such as a laptop, a list of things for sale?

Your composition solution for this one seems kind of backwards to me, as well. I would think of an Inventory as having information on (Holding references to) many different Products. It might also hold information that the Product itself does not know. (How many XYZ_Laptop_Products are in stock? How many are we getting in next week?)

BTW, for a concrete example, XYZ_Laptop_Product might inherit from Electronic_Product, which might inherit from Product. Then again, you might only have one Product class, and the only ways in which a laptop differs from a pair of socks are the stock number, price, and description fields.

2
  • 4
    I did read some of the questions, but none seems to satisfy the curiosity :). I'm really sorry for my bad choice of class noun, but what I meant as Inventory, might be better put as a singular InventoryItem. About the concrete example, Electronic_Product is an abstract I assumed? Nov 11, 2013 at 7:19
  • Electronic_Product is not necessarily an abstract class here. An ElectricProduct can be a class that makes use of fields already present on the Product class then simply adds more fields/methods to it. The Laptop_Product here inherits from ElectricProduct in the same way that ElectricPoduct inherits from Product
    – Maru
    Nov 11, 2013 at 8:53
3

Maybe it would help if we implemented one of the above into a inheritance coding case.

Let's expand on item 2.

Customer's a basic object. Let says it has the following properties:

Customer { 
customer_number, 
debt, 
name, 
age. 
}

Creating a customer (Constructor):

Customer(customer_number, debt, name, age){...}

It can buy:

//Purchase item means adding to the customer's debt to the store.
buy(Object o)
{
    debt = debt + o.price;
} 

Return:

//Return item means reducing the customer's debt (adding credit), minus a 10% restocking fee.
return(Object o)
{
    debt = debt - o.price * 0.9;
}

It can do things like, print name, store debt/credit etc.

double get_debt()
{
    return debt;
}

It has a minimal memory footprint as an object as it only contains four initialised properties, and basic level function.

But now we want to expand the Customer class into a Member class, it has new benefits to being a member, you have status points. And you don't have to pay a restocking fee. So everytime you buy something as a Member object, this gets automatically functioned.

Member extends Customer {
    status_points;
}

You would want the ability to create a Member from scratch, or from an existing customer. Super calls the parent's method/constructor.

Member(customer_number, debt, name, age, new_status_points) {
    super(customer_number, debt, name, age);
    status_points = new_status_points);
}

Member(Customer a, new_status_points){
    super(a.customer_name, a.debt, a.name, a.age);
    status_points = new_status_points;
}

Member's buy function changes (super calls the parent class):

@Override
buy(Object o)
{
    super.buy(o);
    status_points = status_points + o.price / 10;
}

Member's return function with the member's bonus of no return fee.

@Override
return(Object o)
{
   debt = debt - o.price;
   status_points = status_points - o.price / 10;
}

Member also has an addition function, printing their status level.

print_status()
{
    if(status_level < 1000)
    {
         Print("Bronze");
    }
    else if(status_level < 5000)
    {
         Print("Silver");
    }
    else
    {
         Print("Gold");
    }
}

So extra functionality is added without having to recode and retest the basics.

2
  • 1
    I did this before, but stumbled on entity continuity issue. Say we created a Customer object with Id = 1. When we wanted to upgrade the that customer to a member, the code says we needed to create a new object of type Member even though it derived from Customer. Creating a member with Id = 1 would be wrong, because a Customer with that Id is already existed. Deleting the previous Customer object before seems kind of risky.. Nov 11, 2013 at 6:29
  • @SamuelAdam: This sounds like a problem with your data store. If SQL use a transaction to safely delete and reinsert the object. Or depending on how it works force it to load ID 1 into a Member object instead of the default Customer. And your in memory objects should allow making a copy. So copy construct a Member from a Customer then write that back to the data store.
    – Zan Lynx
    Nov 11, 2013 at 14:43
2

If you search around for inheritance from concrete classes, you will find that you are not alone in your question.

In fact, in the large majority of cases, inheritance trees are only 2 or 3 levels deep and only the leaf classes (those that are not used as base class) tend to be concrete.

Inheritance is mostly a powerful tool because it can bring common interfaces or abstractions to light.

1
  • I tried to search, and I'm glad that I'm not a freakshow out here :D Nov 11, 2013 at 13:37
2

I think you should google Peter Coad and read his excellent articles on color data modelling. A good introduction is http://www.step-10.com/SoftwareDesign/ModellingInColour/

Although not explicitly stated in the above article, a Coad modelling workshop I attended used some simple tests to decide when inheritance was the right way to model the data:

  • Inheritance should be used sparingly. Part of this reasoning is to accommodate modern OO languages that only support single inheritance.
  • Inheritance should only be used when the subclass applies for the full life of an object. For instance Cat and Dog can extend Animal, as a cat never becomes a dog. But Manager should not extend Employee, as an employee can become a manager. Manager is an employee playing a time-constrained role, not an inheritance relationship. Coad has invented role and moment-interval classes for modelling such roles.

As you note, changing the class type of an entity at runtime feels wrong, and is definitely code smell.

1

I wouldn't worry too much about inheritance. Polymorphism is more about interfaces than inheritance. (Okay, sometimes a class will do the job and the interface is redundant, but in that case the class is really doing an interface's job in addition to a class's job.)

I find myself using inheritance in two cases:

In the first, I'm writing a new class, and an old class already does about half the work of the new one. So I inherit from the old class and my new one is half written. More commonly, I notice that I've got a bunch of classes with duplicate code. So I pull that code into a single class and make all the others inherit from it. (In most languages you can ony inherit from one other class, so you have to be a bit careful about this.)

In the second I have a class that does the job, but in some cases its calculations are wrong. So I create a new class that inherits from the first and overrides the wrong (in this one case) method. (Alternatively, you could make the first class more flexible. Pick the method that gives you the cleanest code. Some languages make inheritance easier than others.)

I'm sure there are other reasons, but for me, those are the most common.

1
  • 1
    Your examples are good places to consider composition instead of inheritance.
    – user22815
    Dec 2, 2014 at 15:47
0

One of the best examples I've read described things this way (paraphrased) using a zoo:

The base class was Animal. It has (properties) of size and color. It could (methods) eat, sleep, and reproduce.

Now, we have different animals in the zoo.

Monkeys, Tigers, Dolphins.

As classes, they inherited from Animal, so they all had size and color and they could all eat, sleep, and reproduce.

For fields, we consider these: Dolphins have fins and blowholes Monkeys and Tigers have tails Tigers have Claws.

For methods in the class we could consider these things: Monkeys could also (method) climb. Tigers could also climb and they also hunt. Dolphins could swim. So can tigers.

Now, Dolphins can't climb, so climbing would not be something you could move to the parent (Animal) class, but you could put them in the Monkey and Tiger class.

They are ALL Animals, so they all share SOME properties, but they each have some different properties NOT shared by all animals.

Likewise, they can all do some of the same things - like eating and reproducing, but some things only certain animals can do - like swim, and climb - so those things would be tied to each specific animal and NOT ALL Animals.

In your case, let's look at the Employee structure.

All Employees would have an employee ID, name, other related info about the employee.

A generic employee could possibly have these methods: ClockIn ClockOut

A Clerk would be a class inherited from employee would have all the above but perhaps might also have properties for certifications on certain pieces of equipment - registers, scanners, etc - these COULD be handled other ways as well, but working within inheritance we shall simplify it here.

A clerk would be able to RingUp ProcessReturns SearchInventory

A Manager could either be inherited from Clerk or directly from Employee... perhaps they could both inherit from an interface (assuming such is available in the language of choice) or from other classes as well... IClerkDuties - which defines Ringup, ProcessReturns, and SearchInventory but does not implement them.

And then the manager would have IClerkDuties and IManagerDuties. IManagerDuties could have such things as HireEmployee, BerateEmployee, FireEmployee, RateEmployeePerformance...

BUT, all of these would be EMPLOYEES - and any code needing to affect or use the employee class would work on or with all of these.

2
  • Inheritance of employees gets messy when you want to promote or demote an employee, or even move them to a completely different role entirely. You need a whole raft of functions to create new types of employees from others. By switching to composition, rather than inheritance, you can make all the roles into properties that an employee may or may not have. Re-grading then just becomes adding or subtracting roles on an existing employee.
    – Simon B
    Dec 2, 2014 at 12:40
  • There are a dozen ways to skin a cat. My response was more a clarification on what inheritance is and how it applies, as there seemed to be some question about that - there seemed to be confusion between the differences of the class definition itself, and an instantiation thereof. The better answer would be to use a combination of both. Employees will be employees - what job they hold should be part of that class, not the defining class itself.
    – wopanese
    Jan 8, 2015 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.