简体   繁体   中英

Design pattern to use instead of multiple inheritance

Coming from a C++ background, Im used to multiple inheritance. I like the feeling of a shotgun squarely aimed at my foot. Nowadays, I work more in C# and Java, where you can only inherit one baseclass but implement any number of interfaces (did I get the terminology right?).

For example, lets consider two classes that implement a common interface but different (yet required) baseclasses:

public class TypeA : CustomButtonUserControl, IMagician
{
    public void DoMagic()
    {
        // ...
    }
}

public class TypeB : CustomTextUserControl, IMagician
{
    public void DoMagic()
    {
        // ...
    }
}

Both classes are UserControl s so I cant substitute the base class. Both needs to implement the DoMagic function. My problem now is that both implementations of the function are identical. And I hate copy-and-paste code.

The (possible) solutions:

  1. I naturally want TypeA and TypeB to share a common baseclass, where I can write that identical function definition just once. However, due to having the limit of just one baseclass, I cant find a place along the hierarchy where it fits.
  2. One could also try to implement a sort of composite pattern . Putting the DoMagic function in a separate helper class, but the function here needs (and modifies) quite a lot of internal variables/fields. Sending them all as (reference) parameters would just look bad.
  3. My gut tells me that the adapter pattern could have a place here, some class to convert between the two when necessary. But it also feels hacky.

I tagged this with language-agnostic since it applies to all languages that use this one-baseclass-many-interfaces approach.

Also, please point out if I seem to have misunderstood any of the patterns I named.

In C++ I would just make a class with the private fields, that function implementation and put it in the inheritance list. Whats the proper approach in C#/Java and the like?

You can use the strategy pattern or something like it to use has a (composition) instead of is a (inheritance):

public class TypeA : CustomButtonUserControl, IMagician {
    IMagician magicObj = new Magical();
    public void DoMagic() {
        magicObj.DoMagic();
    }
}

public class TypeB : CustomButtonUserControl, IMagician {
    IMagician magicObj = new Magical();
    public void DoMagic() {
        magicObj.DoMagic();
    }
}

public class Magical : IMagician {
    public void DoMagic() {
        // shared magic
    }
}

There are other ways to instantiate your private IMagician members (such as passing them as a param via constructor) but the above should get you started.

  • In .Net, you can have extension methods apply to interfaces. It's really neat when it's possible, and applicable for you because it's a rare way to apply a common implementation to an interface. Certainly consider it, but it might not work for you since you say that DoMagic works with a lot of Private members. Can you package these private variables internal possibly? This way the extension method could access them.
  • Have the common functionality in another class. If there's a logical place to put this common functionality, pass your objects to this other class method (perhaps this is UI functionality, and you already have a UI helper . . .). Again, can you expose the private data with an internal/public property? (Security/encapsulation is a concern in all this of course. I don't know if your classes are for internal use only or will be exposed publicly.)
  • Otherwise, pass a separate functionality class (or specific function pointer) into the interface-defined method. You would have to have a little bit of duplicated code to pass your private variables to this external function reference, but at least it wouldn't be much, and your implementation would be in one place.
  • We might be making this too complicated. It won't make you feel all object-oriented when you go to sleep tonight, but could you have a static routine in your library somewhere that all IMagician implementers call?
  • In the end, Adapter might indeed be what you're looking for. Less likely but still worth consideration is the Decorator pattern .

If nothing seems particularly good, pick what feel best, use it a couple times, and rearrange tomorrow. :)

Replace inheritance with composition.

Move your 'common' function to separate class, create an instance of that class, and insert it to TypeA object and to TypeB object.

Your gut is correct in this case. The Adapter pattern is what you're looking for.

DoFactory has good .NET examples (that should be pretty close to their Java counterparts as well):

Adapter Design Pattern in C# and VB.NET

The composite pattern is meant for complex objects, that means the focus is on one object being made up of other objects. The strategy-pattern can be regarded as a special case of that, but a strategy does not have to be an object. I think this would apply more to your case. Then again, this heavily depends on the nature of what DoMagic() does.

public interface  IMagician{ /* declare here all the getter/setter methods that you need; they will be implemented both in TypeA and TypeB, right? */ }

public static class MyExtensions {
  public static void doMagic(this IMagician obj)
  { 
           // do your magic here
  }
}   

Now, the problem is if you REALLY need to use private properties/methods (as opposed to "internal" ones), this approach won't work. Well, actually, you may be able to do your magic if you can read those properties through reflection, but even if it works, it's a rather ugly solution :)

[Note that "doMagic" will automatically appear to become a part of TypeA and TypeB,simply because you implement IMagician - there is no need to have any implementation there ]

You can use composition to have magician as a property of typeA and typeB

class Magician : IMagician
{
    public void DoMagic()
    {}
}

Class TypeA : CustomButtonUserControl
{
   //property
   Magician magicianInTypeA
}

Class TypeB : CustomTextUserControl
{
    //property
    Magician magicianInTypeB
}
abstract class Magical: CustomButtonUserControl
{
    public void DoMagic()
    {
        // ...
    }
}

public class TypeA : Magical
{

}

public class TypeB : Magical
{

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM