Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object Oriented Best Practices - Inheritance v Composition v Interfaces [closed]

I want to ask a question about how you would approach a simple object-oriented design problem. I have a few ideas of my own about what the best way of tackling this scenario, but I would be interested in hearing some opinions from the Stack Overflow community. Links to relevant online articles are also appreciated. I'm using C#, but the question is not language specific.

Suppose I am writing a video store application whose database has a Person table, with PersonId, Name, DateOfBirth and Address fields. It also has a Staff table, which has a link to a PersonId, and a Customer table which also links to PersonId.

A simple object oriented approach would be to say that a Customer "is a" Person and therefore create classes a bit like this:

class Person {     public int PersonId { get; set; }     public string Name { get; set; }     public DateTime DateOfBirth { get; set; }     public string Address { get; set; } }  class Customer : Person {     public int CustomerId { get; set; }     public DateTime JoinedDate { get; set; } }  class Staff : Person {     public int StaffId { get; set; }     public string JobTitle { get; set; } } 

Now we can write a function say to send emails to all customers:

static void SendEmailToCustomers(IEnumerable<Person> everyone) {      foreach(Person p in everyone)         if(p is Customer)             SendEmail(p); } 

This system works fine until we have someone who is both a customer and a member of staff. Assuming that we don't really want our everyone list to have the same person in twice, once as a Customer and once as a Staff, do we make an arbitrary choice between:

class StaffCustomer : Customer { ... 

and

class StaffCustomer : Staff { ... 

Obviously only the first of these two would not break the SendEmailToCustomers function.

So what would you do?

  • Make the Person class have optional references to a StaffDetails and CustomerDetails class?
  • Create a new class that contained a Person, plus optional StaffDetails and CustomerDetails?
  • Make everything an interface (e.g. IPerson, IStaff, ICustomer) and create three classes that implemented the appropriate interfaces?
  • Take another completely different approach?
like image 773
Mark Heath Avatar asked Oct 19 '08 15:10

Mark Heath


People also ask

Which is better inheritance or composition?

Composition offers better test-ability of a class than Inheritance. If one class consists of another class, you can easily construct a Mock Object representing a composed class for the sake of testing.

Why do we prefer composition more than inheritance in object-oriented design?

To favor composition over inheritance is a design principle that gives the design higher flexibility. It is more natural to build business-domain classes out of various components than trying to find commonality between them and creating a family tree.

What is the difference between composition and inheritance in OOP?

Inheritance and composition are two programming techniques developers use to establish relationships between classes and objects. Whereas inheritance derives one class from another, composition defines a class as the sum of its parts.

What are the 3 Oops principles?

Encapsulation, inheritance, and polymorphism are usually given as the three fundamental principles of object-oriented languages (OOLs) and object-oriented methodology.


2 Answers

Mark, This is an interesting question. You will find as many opinions on this. I don't believe there is a 'right' answer. This is a great example of where a rigid heirarchial object design can really cause problems after a system is built.

For example, lets say you went with the "Customer" and "Staff" classes. You deploy your system and everything is happy. A few weeks later, someone points out that they are both 'on staff' and a 'customer' and they are not getting customer emails. In this case, you have a lot of code changes to make (re-design, not re-factor).

I believe it would be overly complex and difficult to maintain if you attempt to have a set of derived classes that implement all the permutations and combination of people and their roles. This is especially true given that the above example is very simple - in most real applications, things will be more complex.

For your example here, I would go with "Take another completely different approach". I would implement the Person class and include in it a collection of "roles". Each person could have one or more roles such as "Customer", "Staff", and "Vendor".

This will make it easier to add roles as new requirements are discovered. For example, you may simply have a base "Role" class, and derive new roles from them.

like image 95
Foredecker Avatar answered Sep 19 '22 05:09

Foredecker


You may want to consider using the Party and Accountability patterns

This way Person will have a collection of Accountabilities which may be of type Customer or Staff.

The model will also be simpler if you add more relationship types later.

like image 43
Jorge Villuendas Zapatero Avatar answered Sep 21 '22 05:09

Jorge Villuendas Zapatero