Mam klasę: A
jest to połączenie wielu mniejszych klas B
, C
i D
.
B
, C
I D
wdrożyć interfejsów IB
, IC
oraz ID
odpowiednio.
Ponieważ A
obsługuje wszystkie funkcje B
, C
i D
, A
narzędzi IB
, IC
a ID
także, ale to niestety prowadzi do wielu re-routing w realizacjiA
Tak jak:
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;}
}
}
Czy istnieje sposób, aby pozbyć się przekierowania z płyty A
? B
, C
i D
wszystkie implementują różne, ale wspólne funkcje, i podoba mi się to A
implementacja IB
, IC
a ID
ponieważ oznacza to, że mogę przekazać A
samą siebie jako zależność pasującą do tych interfejsów i nie muszę ujawniać wewnętrznych metod pomocniczych.
c#
design-patterns
patterns-and-practices
composition
Nick Udell
źródło
źródło
A
wdrożyćIB
,IC
aID
to wydaje się bardziej sensowne napisaćPerson.Walk()
w przeciwieństwie doPerson.WalkHelper.Walk()
, na przykład.Odpowiedzi:
To, czego szukasz, jest powszechnie nazywane mixinami . Niestety C # natywnie nie obsługuje tych.
Istnieje kilka obejść: jeden , dwa , trzy i wiele innych.
Naprawdę podoba mi się ostatni. Pomysł użycia automatycznie generowanej klasy cząstkowej do wygenerowania płyty kotłowej jest prawdopodobnie najbliższy naprawdę dobremu rozwiązaniu:
źródło
Chociaż nie redukuje to w samym kodzie, Visual Studio 2015 zawiera teraz opcję refaktoryzacji, aby automatycznie wygenerować dla ciebie płytkę.
Aby z tego skorzystać, najpierw utwórz interfejs
IExample
i implementacjęExample
. Następnie utwórz nową klasęComposite
i wprowadź ją do dziedziczeniaIExample
, ale nie implementuj interfejsu.Dodaj właściwość lub pole typu
Example
do swojejComposite
klasy, otwórz menu szybkich działań na tokenieIExample
wComposite
pliku klasy i wybierz „Implementuj interfejs poprzez„ Przykład ”, gdzie„ Przykład ”w tym przypadku jest nazwą pola lub właściwości.Należy pamiętać, że chociaż program Visual Studio wygeneruje i przekieruje wszystkie metody i właściwości zdefiniowane w interfejsie do tej klasy pomocniczej, nie przekieruje zdarzeń w momencie opublikowania tej odpowiedzi.
źródło
Twoja klasa robi za dużo, dlatego musisz zaimplementować tak wiele płyt grzewczych. W komentarzach mówisz:
Nie zgadzam się. Chodzenie prawdopodobnie wiąże się z wieloma regułami i nie należy do
Person
klasy - należy doWalkingService
klasy, wwalk(IWalkable)
której metoda implementuje OsobaIWalkable
.Podczas pisania kodu zawsze miej na uwadze SOLIDNE zasady. Dwa, które są tutaj najbardziej odpowiednie, to Separation of Concerns (wyodrębnij kod przejścia do osobnej klasy) i Segregacja interfejsu (podzielone interfejsy na określone zadania / funkcje / umiejętności). Wygląda na to, że możesz mieć część I z wieloma interfejsami, ale potem cofasz całą swoją dobrą pracę, wprowadzając je w jednej klasie.
źródło
walk(IWalkable)
metody, osobiście jej nie lubię, ponieważ wówczas usługi chodzenia stają się obowiązkiem dzwoniącego, a nie Osoby, a konsekwencja nie jest gwarantowana. Każdy dzwoniący musiałby wiedzieć, z której usługi skorzystać, aby zagwarantować spójność, podczas gdy zachowanie jej w klasie Person oznacza, że należy ją ręcznie zmienić, aby zachować zachowanie podczas chodzenia, jednocześnie umożliwiając odwrócenie zależności.To, czego szukasz, to wielokrotne dziedziczenie. Jednak ani C #, ani Java nie mają tego.
Możesz przedłużyć B od A. To wyeliminuje potrzebę prywatnego pola dla B, a także kleju przekierowującego. Ale możesz to zrobić tylko dla jednego z B, C lub D.
Teraz, jeśli możesz sprawić, że C odziedziczy po B, a D po C, to musisz mieć tylko A przedłużyć D ...;) - dla jasności, tak naprawdę nie zachęcam do tego w tym przykładzie, ponieważ nic nie wskazuje dla tego.
W C ++ możesz mieć A odziedziczone po B, C i D.
Ale wielokrotne dziedziczenie sprawia, że programy są trudniejsze do uzasadnienia i ma swoje własne problemy; Ponadto często istnieje czysty sposób, aby tego uniknąć. Mimo to, czasami bez niego, konieczne jest dokonanie kompromisów projektowych między powtarzającym się szablonem a sposobem wyświetlania modelu obiektowego.
To trochę tak, jakbyś próbował połączyć kompozycję i dziedzictwo. Gdyby to był C ++, można użyć czystego rozwiązania dziedziczenia. Ale skoro tak nie jest, polecam przyjęcie kompozycji.
źródło