23 Stimmen

Entwurfsmuster, das anstelle der Mehrfachvererbung zu verwenden ist

Ich komme aus einem C++-Hintergrund und bin an Mehrfachvererbung gewöhnt. Ich mag das Gefühl einer Schrotflinte, die direkt auf meinen Fuß gerichtet ist. Heutzutage arbeite ich mehr in C# und Java, wo man nur eine Basisklasse erben, aber eine beliebige Anzahl von Schnittstellen implementieren kann (habe ich die Terminologie richtig verstanden?).

Nehmen wir zum Beispiel zwei Klassen, die eine gemeinsame Schnittstelle implementieren, aber unterschiedliche (aber erforderliche) Basisklassen:

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

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

Beide Klassen sind UserControl s, so dass ich die Basisklasse nicht ersetzen kann. Beide müssen die DoMagic Funktion. Mein Problem ist nun, dass beide Implementierungen der Funktion identisch sind. Und ich hasse Copy-and-Paste-Code.

Die (möglichen) Lösungen:

  1. Ich möchte natürlich TypeA y TypeB eine gemeinsame Basisklasse zu teilen, in der ich die identische Funktionsdefinition nur einmal schreiben kann. Aufgrund der Beschränkung auf nur eine Basisklasse kann ich jedoch keinen Platz in der Hierarchie finden, an den sie passt.
  2. Man könnte auch versuchen, eine Art von zusammengesetztes Muster . Das Einsetzen der DoMagic Funktion in einer separaten Hilfsklasse, aber die Funktion hier benötigt (und ändert) eine ganze Reihe von internen Variablen/Feldern. Sie alle als (Referenz-)Parameter zu senden, würde einfach schlecht aussehen.
  3. Mein Gefühl sagt mir, dass die Adapterschema könnte hier einen Platz haben, eine Klasse, die bei Bedarf zwischen den beiden konvertiert. Aber es fühlt sich auch hakelig an.

Ich habe dies als sprachenunabhängig gekennzeichnet, da es für alle Sprachen gilt, die diesen Ansatz "eine Basisklasse - viele Schnittstellen" verwenden.

Bitte weisen Sie mich auch darauf hin, wenn ich eines der von mir genannten Muster missverstanden habe.

In C++ würde ich einfach eine Klasse mit den privaten Feldern und der Funktionsimplementierung erstellen und sie in die Vererbungsliste aufnehmen. Was ist der richtige Ansatz in C#/Java und dergleichen?

1voto

Virgil Punkte 2992
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
  }
}   

Das Problem ist, wenn Sie WIRKLICH private Eigenschaften/Methoden (im Gegensatz zu den "internen") verwenden müssen, wird dieser Ansatz nicht funktionieren. Nun, eigentlich, Sie können in der Lage sein, Ihre Magie zu tun, wenn Sie diese Eigenschaften durch Reflexion lesen können, aber selbst wenn es funktioniert, es ist eine ziemlich hässliche Lösung :)

[Beachten Sie, dass "doMagic" automatisch ein Teil von TypeA und TypeB zu werden scheint, einfach weil Sie IMagician implementieren - es besteht keine Notwendigkeit, dort eine Implementierung zu haben.]

0voto

AlwaysAProgrammer Punkte 2881

Sie können Komposition verwenden, um Magier als Eigenschaft von TypA und TypB zu haben

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

Class TypeA : CustomButtonUserControl
{
   //property
   Magician magicianInTypeA
}

Class TypeB : CustomTextUserControl
{
    //property
    Magician magicianInTypeB
}

-3voto

Itay Moav -Malimovka Punkte 50743
abstract class Magical: CustomButtonUserControl
{
    public void DoMagic()
    {
        // ...
    }
}

public class TypeA : Magical
{

}

public class TypeB : Magical
{

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X