Ich habe eine Klasse: A
das ist eine Mischung aus mehreren kleineren Klassen B
, C
und D
.
B
, C
Und D
Schnittstellen implementieren IB
, IC
und ID
jeweils.
Da A
unterstützt alle Funktionen von B
, C
und D
, A
implementiert IB
, IC
und ID
auch, aber dies leider führt zu einer viel Umleiten bei der Umsetzung derA
Wie so:
interface IB
{
int Foo {get;}
}
public class B : IB
{
public int Foo {get {return 5;}}
}
interface IC
{
void Bar();
}
public class C : IC
{
public void Bar()
{
}
}
interface ID
{
string Bash{get; set;}
}
public class D: ID
{
public string Bash {get;set;}
}
class A : IB, IC, ID
{
private B b = new B();
private C c = new C();
private D d = new D();
public int Foo {get {return b.Foo}}
public A(string bash)
{
Bash = bash;
}
public void Bar()
{
c.Bar();
}
public string Bash
{
get {return d.Bash;}
set {d.Bash = value;}
}
}
Gibt es eine Möglichkeit, diese Umleitung von Boilerplates in loszuwerden A
? B
, C
Und D
implementieren alle unterschiedlich , aber gemeinsame Funktionalität, und ich mag , dass A
Geräte IB
, IC
und ID
weil es bedeutet , kann ich in übergeben A
sich als Abhängigkeit diese Schnittstellen übereinstimmt, und müssen nicht die inneren Hilfsmethoden aus.
c#
design-patterns
patterns-and-practices
composition
Nick Udell
quelle
quelle
A
umzusetzenIB
,IC
undID
ist es sinnvoller zu schreiben fühlt ,Person.Walk()
im Gegensatz zuPerson.WalkHelper.Walk()
, zum Beispiel.Antworten:
Was Sie suchen, wird allgemein als Mixins bezeichnet . Leider unterstützt C # diese nicht von Haus aus.
Es gibt nur wenige Problemumgehungen: eine , zwei , drei und viele mehr.
Ich mag den letzten wirklich sehr. Die Idee, automatisch generierte Teilklassen zum Generieren der Boilerplate zu verwenden, kommt wahrscheinlich einer tatsächlich guten Lösung am nächsten:
quelle
Visual Studio 2015 enthält jetzt eine Refactoring-Option, mit der das Boilerplate automatisch für Sie generiert werden kann.
Um dies zu verwenden, erstellen Sie zuerst Ihre Schnittstelle
IExample
und ImplementierungExample
. Erstellen Sie dann Ihre neue KlasseComposite
und lassen Sie sie erbenIExample
, implementieren Sie die Schnittstelle jedoch nicht.Fügen Sie
Example
IhrerComposite
Klasse eine Eigenschaft oder ein Feld vom Typ hinzu , öffnen Sie das Schnellmenü auf dem TokenIExample
in IhrerComposite
Klassendatei und wählen Sie "Schnittstelle durch 'Beispiel' implementieren", wobei 'Beispiel' in diesem Fall der Name des Felds oder der Eigenschaft ist.Sie sollten beachten, dass Visual Studio zwar alle in der Schnittstelle definierten Methoden und Eigenschaften für diese Hilfsklasse generiert und umleitet, jedoch keine Ereignisse zum Zeitpunkt der Veröffentlichung dieser Antwort umleitet.
quelle
Ihre Klasse macht zu viel, deshalb müssen Sie so viel Boilerplate implementieren. Sie sagen in den Kommentaren:
Ich stimme dir nicht zu. Das Gehen beinhaltet wahrscheinlich viele Regeln und gehört nicht zur
Person
Klasse - es gehört zu einerWalkingService
Klasse mit einerwalk(IWalkable)
Methode, die Person implementiertIWalkable
.Beachten Sie beim Schreiben von Code immer die SOLID-Prinzipien. Die beiden hier am besten geeigneten sind die Trennung von Bedenken (Extrahieren des Laufcodes in eine separate Klasse) und die Schnittstellentrennung (Aufteilung der Schnittstellen in bestimmte Aufgaben / Funktionen / Fähigkeiten). Es hört sich so an, als hätten Sie vielleicht einiges von I mit Ihren mehreren Schnittstellen, machen dann aber all Ihre gute Arbeit rückgängig, indem Sie sie von einer Klasse implementieren lassen.
quelle
walk(IWalkable)
Methode gefällt mir persönlich nicht, da dann die Gehdienste in die Verantwortung des Anrufers und nicht der Person fallen und die Konsistenz nicht garantiert ist. Jeder Anrufer müsste wissen, welchen Dienst er verwenden soll, um die Konsistenz zu gewährleisten. Wenn er jedoch in der Person-Klasse bleibt, muss er manuell geändert werden, damit sich das Gehverhalten unterscheidet, und gleichzeitig die Abhängigkeitsinversion zulassen.Was Sie suchen, ist Mehrfachvererbung. Weder C # noch Java haben es jedoch.
Sie können B von A erweitern. Dadurch entfällt die Notwendigkeit eines privaten Felds für B sowie des Umleitungsklebers. Sie können dies jedoch nur für B, C oder D tun.
Wenn Sie nun C von B und D von C erben lassen können, müssen Sie nur A verlängern D ...;) - nur um klar zu sein, ich ermutige das in diesem Beispiel nicht wirklich, da es keinen Hinweis gibt dafür.
In C ++ kann A von B, C und D erben.
Die Mehrfachvererbung erschwert jedoch das Nachdenken über Programme und hat ihre eigenen Probleme. Außerdem gibt es oft einen sauberen Weg, dies zu vermeiden. Manchmal muss man jedoch ohne sie Design-Kompromisse zwischen der Wiederholung der Boilerplate und der Belichtung des Objektmodells eingehen.
Es fühlt sich ein bisschen so an, als würden Sie versuchen, Komposition und Vererbung zu mischen. Wenn dies C ++ wäre, könnten Sie eine reine Vererbungslösung verwenden. Aber da dies nicht der Fall ist, würde ich empfehlen, sich der Komposition zuzuwenden.
quelle