0

I've heard of the pitfalls of multiple inheritance before, and I know the .Net devs are against it's inclusion.

With that said, consider a simple example such as 'Game Companies'. A game company can be:

  • a software developer, like Platinum Games
  • a publisher, like for instance Agetec
  • a developer AND publisher at the same time, as in Blizzard Entertainment
  • a gaming hardware manufacturer only (don't have examples of a company that is solely a manufacturer in hand)
  • all of the above, i.e. Nintendo

If I had to model this in .Net, how would I go about the fact that the "is a" relationship is present and a company can be multiple of those at the same time? Imagine that I have modeled a:

  1. Game class, having List<Developer> and Publisher as properties
  2. Console class that had a Manufacturer property.

In an ideal scenario, this should be as type safe as possible and easy to filter and navigate to and from each class (like a fully connected Entity Framework mapping of sorts).

I thought about something in the same vein, for which I probably known the 'right' answer.

What if I had FatPerson and TallPerson as base classes and wanted to 'work around' the multiple inheritance limitation? Because it's quite possible to have someone who is both fat and tall at the same time. In this case, it would probably be cleaner if there was a single Person had two properties, Weight and Height, eliminating the base classes altogether. It would be just a matter of rewriting whatever filtering I had before that was based around the type of the objects to consider these new properties.

Is there something inherently equivalent to this for every multiple inheritance case? What about for this particular case I proposed?

Update:

I've read that answer that is marked as a duplicate of mine (before posting this one), but I disagree slightly here. I think this is the same as marking a SQL optimization question as duplicate of every other SQL optimization question. In the end, each case is a different case, and would require a different approach/answer. I think this applies here since I asked about a very fixed case, like the other answer did.

julealgon
  • 7,072
  • 3
  • 32
  • 77
  • Maybe I didn't understand. Your solution is: if you do not inherit then you won't have multiple inheritance? Anyway...what's the question? – Adriano Repetti Jan 06 '14 at 21:22
  • The particular case you've outlined does not define anything which requires multiple inheritance. For, say, Blizzard, you could just have two objects, BlizzardDeveloper and BlizzardPublisher. What is gained by having one object while inherits both Developer and Publisher? – Heretic Monkey Jan 06 '14 at 21:28
  • If you use properties, you could dodge MI even in a language that provided it, so yes. The real question is do you need methods such as Publish, in which case you squint and say the entity is a publisher if it implements the interface IPublish – Tony Hopkinson Jan 06 '14 at 21:30
  • @MikeMcCaughan Having two classes that are the same 'thing' doesn't make sense to me. I mean, they are the same real world entity, having them separate inside the application gives them another semantic. When I access the `Blizzard` object, I should be able to navigate to their developed and published titles. Perhaps there is a title that was only developed by them, but published by someone else (for instance Interplay, in case of BlackThorne for SNES)? – julealgon Jan 06 '14 at 21:32
  • @Adriano I did not present any solution to the problem at all, just to a toy example I created myself to try and come to the same conclusion _for_ the main problem. – julealgon Jan 06 '14 at 21:34
  • @julealgon. You'd just have titles, if you wanted to select titles developed by X and/or Published by X those would be properties of title, not Game company. When a game company developed or published a title, it would set the relevant property on title – Tony Hopkinson Jan 06 '14 at 21:47
  • Well, I guess I think of them as the same thing acting in different roles. I think @TonyHopkinson has it right that the single Blizzard object could implement both IDeveloper and IPublisher. – Heretic Monkey Jan 06 '14 at 21:54
  • 1
    Large companies create *divisions* to keep the company manageable. Called "encapsulation" in software. – Hans Passant Jan 06 '14 at 22:21
  • @HansPassant Ok, this is more like it. I think that if I went with a realistic model this should be the way to go. Do you have any concrete proposal about how the model would look like? – julealgon Jan 07 '14 at 12:56
  • @TonyHopkinson That would change what I proposed a bit. I wanted to keep everything connected, in a way that I could 'navigate' from the company to it's published and developed titles, and vice-versa (from a title, know who developed and who published it). – julealgon Jan 07 '14 at 13:13
  • 1
    Titles.Where(x => x.Publisher_ID = this.ID), connected. Part of your problem is you are looking at how can I implement this with inheritance instead of what do I need to implement this. Going to use inheritance hammer so this has to be a nail... – Tony Hopkinson Jan 07 '14 at 21:51
  • @TonyHopkinson Fair enough, I think I'm indeed biased here on using MI to solve this, will certainly think of alternatives when it comes to start coding the solution. So, what do you propose? A single `GameCompany` class of sorts (whitout inherent distinction if it is a publisher/manufacturer/etc) and multiple properties on the `Title`/`Game` class, indicating which company published and developed it? Then, to find if a company is a publisher it would be a matter of finding if there are any titles published by that company for example, right? – julealgon Jan 08 '14 at 13:06

1 Answers1

1

This scenario is a good example for Role Based Software Engineering which is a current topic in research. That's because there is no one and only solution to the problem. There are several approaches, but all of them have their drawbacks.

Interfaces are a good way to design the relation of types. If you make e.g. Developer and Publisher interfaces, there can be companies that are both. However, you cannot inherit code from interfaces and you usually end up with lots of duplicate code.

Going one step further, you come up with mixin inheritance. That's basically interface implementation augmented with extension methods. Take a look at this example:

class Company { }

interface Publisher { }
public static class PublisherMixin
{
    public static void Publish(this Publisher p) 
    {
        //do something
    }
}

class CompanyThatIsAPublisher : Company, Publisher { }

And then you can do

var c = new CompanyThatIsAPublisher():
c.Publish();

You can do this for several mixins. You can even provide state for the mixins with the help of weak reference dictionaries.

Another way to avoid code duplication is delegation. You still have your interface hierarchy, but create objects for the developer role, the publisher role etc. The company then just forwards method calls to these sub-objects. However, this results in object schizophrenia. The sub-objects do not really belong to the main object which can pose a problem. However you can easily exchange them.

In C# you could also use a DynamicObject. With this you could dynamically register roles and dynamically reroute method calls to the appropriate objects. So a developer company can become a publisher eventually without having to loose its identity. This approach also suffers from the object schizophrenia problem.

Nico Schertler
  • 32,049
  • 4
  • 39
  • 70
  • Very nice, I've seen this mixin approach before. Do you have any suggestions to make it more test friendly though? I always thought that these extension methods were meant for small, pure methods without side effects. The `Publish` method there could potentially have complex code, and it would not be possible to mock away the behavior out of the main classes during testing this way. – julealgon Jan 07 '14 at 13:11
  • 1
    You could add a mock class with the same methods as the mixin. The compiler will choose class methods before extension methods. – Nico Schertler Jan 07 '14 at 15:59