Gute Objektstruktur für selektive Komposition ohne Klassenexplosion

9

Mein wirkliches Szenario ist ein bisschen schwer zu erklären, also werde ich es einer besser erkennbaren Domäne zuordnen, sagen wir Unterhaltungselektronik:

Ein bestimmtes Gerät kann verschiedene Dienste anbieten:

Ein Panasonic XYZ kann DVDs und CDs abspielen.
Ein Sony ABC kann nur CDs abspielen.
Ein Hitachi PQR kann DVDs abspielen und TV empfangen.
...
...

Jeder Dienst (DVD, CD, TV, ...) hat eine Standardimplementierung, die von den meisten Modellen verwendet wird, aber einige Modelle haben angepasste Versionen bestimmter Dienste.


Schnittstellen

Modelle, die DVD-fähige, CD-fähige, TV-fähige, ... Verträge implementieren möchten führen zu einer Menge Code-Duplizierung zwischen Modellen.


Einzelne Vererbung

Eine einzige Superklasse, die die Standarddienste implementiert, würde mir erlauben, für jedes Modell eine einzige Unterklasse zu haben, die all ihr benutzerdefiniertes Verhalten enthält. Meine Superklasse wäre jedoch sehr unhandlich und schwerer, als es für Modelle sein muss, die nicht alle Arten von Dienstleistungen anbieten.


Mehrfachvererbung

Mehrfachvererbung mit ihrer Fähigkeit, die erforderlichen Dienste selektiv einzubeziehen und Standardimplementierungen auf der Oberfläche bereitzustellen, scheint ideal. Ich schätze die Kohäsion, alle Funktionen von PanasonicXYZ in einer einzigen Klasse zu haben, mehr als die durch die Vererbung eingeführte Kopplung.

Aber ich benutze kein C ++ (eher PHP) und irgendwie habe ich den Eindruck, dass es einen besseren Weg gibt. Ich möchte auch keine proprietären Erweiterungen wie Mixins oder 5.4-Eigenschaften verwenden.


Komposition

Ich sehe eine Klassenexplosion mit meiner benutzerdefinierten Funktionalität für ein bestimmtes Modell, das über mehrere Klassen verstreut ist - ich würde zum Beispiel eine PanasonicXYZ_CD-Klasse und eine PanasonicXYZ_DVD-Klasse benötigen, die nur vom PanasonicXYZ-Objekt verwendet werden.


Gibt es eine bevorzugte Struktur?

Bearbeiten: Ich werde über einige der Kommentare und Antworten nachdenken, anstatt sie vorzeitig zu kommentieren.

    
jontyc 03.12.2011, 11:50
quelle

6 Antworten

3

Verwenden Sie die Komposition Luke :

Objektklassen repräsentieren eine Rolle in Ihrem System. Selbst wenn es logisch ist, über ein "Gerät" nachzudenken, sollten Sie sich zu OOP-Zwecken überlegen, welche Funktionen Ihr Gerät hat: DVD-Player, Fernsehempfänger, CD-Player usw.

Es spielt keine Rolle, dass ein einzelnes Gerät alle davon ausführt. Wenn Sie in den Rollen denken, die das Objekt haben wird, können Sie mit einzelne Verantwortlichkeitsobjekte enden:

%Vor%

Auf diese Weise lässt sich die allgemeine Funktionalität leicht umgestalten, Sie können eine GenericDVDPlayer haben und diese in der Methode asDVDPlayer zurückgeben.

Wenn Sie eine dynamischere Verwendung zulassen möchten, z. B. fragen Sie nach einer Device -Funktionalität, die sie unterstützt, können Sie eine Art Produkthändler , zum Beispiel:

%Vor%

und sie im Code könnten Sie so etwas tun:

%Vor%

Sehen Sie, dass in diesem Fall das "Multifunktionsgerät" wie ein Produkthändler und das DVDPlayer.class die Spezifikation des Produkts ist .

Es gibt viele verschiedene Möglichkeiten, den Trader und die Spezifikation zu implementieren, zum Beispiel das Muster Besucher . Aber ich habe festgestellt, dass Sie in vielen Fällen (wenn Sie Ihre "Multifunktionsgeräte" dynamisch konfigurieren möchten) etwas tun können:

%Vor%

Dies kombiniert mit einem Builder und einer fließenden API vereinfacht die Definition verschiedener Geräte ohne Klassenexplosion:

%Vor%     
Diego 03.01.2012 22:19
quelle
0

Ich würde die Abhängigkeitsinjektion verwenden, um so etwas zu tun:

%Vor%

Dann erweitern alle Geräte Devices , alle Funktionen erweitern Function . Um eine Standardprozedur Function zu ändern, könnte Ihre Geräteklasse (z. B. SonyAbc) ihre eigenen Methoden für z. dvdPlay() .

    
str 03.12.2011 12:38
quelle
0

Ich würde die Komposition bevorzugen.

Benötigen Sie sogar tatsächliche Klassen für jedes Gerät? Oder wäre es ausreichend, ein bestimmtes TV-Gerät als eine ordnungsgemäß verdrahtete Instanz eines Geräts mit einigen Funktionen bereitzustellen?

%Vor%

Features konnten abgerufen werden, indem

aufgerufen wurde %Vor%     
tkr 03.12.2011 13:15
quelle
0

Sind die Dienste bereits bekannt und in ihrer Anzahl begrenzt? Wenn ja, würde ich so etwas tun:

  • Definieren Sie eine Schnittstelle für jede Art von Dienst (z. B. DVDPlayer, TvReceiver, CdPlayer usw.)

  • Geben Sie jeder Serviceschnittstelle eine Standardimplementierung (die häufig von vielen Geräten gemeinsam genutzte) und codieren Sie die modellspezifischen Implementierungen, die Sie ebenfalls benötigen.

  • Definieren Sie eine zweite Gruppe von Schnittstellen, um anzuzeigen, dass ein bestimmtes Gerät einen Dienst (z. B. DvdPlayerCapable) anbieten kann, wobei jede Schnittstelle ein (eindeutig benanntes) Getter für die Serviceschnittstelle deklariert, z. B .:

    %Vor%
  • Jetzt kann Ihr Gerät mehrere Funktionsschnittstellen kombinieren und entweder die Standardimplementierung des Service oder eine modellspezifische verwenden ...

Wenn Sie zum Beispiel auf Ihrem Sony123Device, das ein DVDPlayerCapable ist, zu DVD Kapitel 15 gehen möchten, können Sie anrufen:

%Vor%     
Simon Baslé 23.12.2011 14:15
quelle
0

Es scheint, dass Sie zwei Probleme haben. Das erste Problem besteht darin, wie Sie die allgemeine Funktionalität zwischen den Diensten weitergeben, die durch Vererbung gelöst werden können. Etwas wie das Folgende:

%Vor%

Der interessante Teil des Problems ist, wo wir in angepasste Versionen der Standardeinstellungen kommen. In diesem Fall möchten wir die Vererbung nicht verwenden, da wir wissen, dass sie direkt gegen LSP verstößt. Wir könnten uns also über eine Komposition annähern, die zu etwas ähnlich dem Folgenden führen würde:

%Vor%

Oder Sie könnten die allgemeine spezielle Funktionalität innerhalb der Dienstprogrammklasse verfügbar machen.

    
Woot4Moo 23.12.2011 15:29
quelle
0

In der Vergangenheit habe ich eine generische Custom_Fuctions für meine abstrakte root -Klasse angegeben. Es ist für den Speicher serialisiert

Ich rufe dann

an %Vor%

Fügen Sie Zoll über Methode hinzu:

%Vor%     
ppostma1 04.01.2012 19:39
quelle

Tags und Links