Sammansatt mönster
Inom mjukvaruteknik är det sammansatta mönstret ett partitioneringsmönster . Det sammansatta mönstret beskriver en grupp av objekt som behandlas på samma sätt som en enda instans av samma typ av objekt. Avsikten med en sammansatt är att "komponera" objekt till trädstrukturer för att representera del-hela hierarkier. Genom att implementera det sammansatta mönstret kan kunderna behandla enskilda objekt och kompositioner enhetligt.
Översikt
Det sammansatta designmönstret är ett av de tjugotre välkända GoF-designmönstren som beskriver hur man löser återkommande designproblem för att designa flexibel och återanvändbar objektorienterad programvara, det vill säga objekt som är lättare att implementera, ändra, testa och återanvändning.
Vilka problem kan det sammansatta designmönstret lösa?
- En del-hel hierarki bör representeras så att klienter kan behandla delar och hela objekt enhetligt.
- En del-hel hierarki bör representeras som trädstruktur.
När man definierar (1) Delobjekt
och (2) Hela
objekt som fungerar som behållare för Delobjekt
måste klienter behandla dem separat, vilket komplicerar klientkoden.
Vilken lösning beskriver Composite-designmönstret?
- Definiera ett enhetligt
komponentgränssnitt
för både del- (Leaf
) objekt och hela (Composite
) objekt. - Individuella
Leaf
-objekt implementerarComponent-
gränssnittet direkt, ochComposite
-objekt vidarebefordrar förfrågningar till sina underordnade komponenter.
Detta gör det möjligt för klienter att arbeta genom komponentgränssnittet
för att behandla Leaf-
och Composite
-objekt enhetligt: Leaf
-objekt utför en begäran direkt, och Composite
-objekt vidarebefordrar begäran till sina underordnade komponenter rekursivt nedåt i trädstrukturen. Detta gör klientklasser lättare att implementera, ändra, testa och återanvända.
Se även UML klass- och objektdiagram nedan.
Motivering
När de hanterar trädstrukturerade data måste programmerare ofta skilja mellan en lövnod och en gren. Detta gör koden mer komplex och därför mer felbenägen. Lösningen är ett gränssnitt som gör det möjligt att behandla komplexa och primitiva objekt enhetligt. I objektorienterad programmering är en komposit ett objekt utformat som en sammansättning av ett eller flera liknande objekt, som alla uppvisar liknande funktionalitet. Detta är känt som ett " har-ett "-förhållande mellan objekt. Nyckelkonceptet är att du kan manipulera en enda instans av objektet precis som du skulle manipulera en grupp av dem. De operationer du kan utföra på alla sammansatta objekt har ofta ett minsta gemensamma nämnarförhållande . Till exempel, om man definierar ett system för att porträttera grupperade former på en skärm, skulle det vara användbart att definiera storleksändring av en grupp av former för att ha samma effekt (i någon mening) som att ändra storlek på en enskild form.
När ska användas
Komposit bör användas när klienter ignorerar skillnaden mellan sammansättningar av objekt och enskilda objekt. Om programmerare upptäcker att de använder flera objekt på samma sätt och ofta har nästan identisk kod för att hantera vart och ett av dem, så är komposit ett bra val; det är mindre komplicerat i denna situation att behandla primitiver och kompositer som homogena.
Strukturera
UML klass och objektdiagram
I ovanstående UML- klassdiagram hänvisar klientklassen inte till Leaf-
och Composite -klasserna direkt
(
separat). Istället hänvisar klienten till det gemensamma
komponentgränssnittet
och kan behandla Leaf
och Composite
enhetligt. Leaf -
klassen har inga barn och implementerar Component
-gränssnittet direkt. Klassen Composite
upprätthåller en behållare med underordnade komponentobjekt
( barn
) och vidarebefordrar förfrågningar till dessa underordnade
( för varje barn i barn: child.operation()
).
Objektsamarbetsdiagrammet visar körtidsinteraktionerna: I det här exemplet skickar klientobjektet en begäran till det
sammansatta
objektet på toppnivån ( av typen Component
) i trädstrukturen. Begäran vidarebefordras till (utförs på) alla underordnade komponentobjekt
( blad
och sammansatta
objekt) nedåt i trädstrukturen.
- Definiera barnrelaterade operationer
Det finns två designvarianter för att definiera och implementera barnrelaterade operationer som att lägga till/ta bort en underordnad komponent till/från behållaren ( add(child)/remove(child))
och åtkomst till en underordnad komponent ( getChild()
):
-
Design för enhetlighet: Barnrelaterade operationer definieras i
komponentgränssnittet
. Detta gör det möjligt för kunder att behandlablad
ochkompositobjekt
enhetligt. Men typsäkerheten går förlorad eftersom klienter kan utföra barnrelaterade operationer påLeaf-
objekt. -
Design för typsäkerhet: Barnrelaterade operationer definieras endast i
Composite
-klassen. Kunder måste behandlaLeaf-
ochComposite
-objekt olika. Men typsäkerhet uppnås eftersom klienter inte kan utföra barnrelaterade operationer påLeaf-
objekt.
Designmönstret i komposit betonar enhetlighet framför typsäkerhet .
UML klassdiagram
- Komponent
- är abstraktionen för alla komponenter, inklusive sammansatta
- deklarerar gränssnittet för objekt i kompositionen
- (valfritt) definierar ett gränssnitt för åtkomst till en komponents överordnade i den rekursiva strukturen, och implementerar det om det är lämpligt
- Blad
- representerar lövobjekt i kompositionen
- implementerar alla komponentmetoder
- Sammansatt
- representerar en sammansatt komponent (komponent som har barn)
- implementerar metoder för att manipulera barn
- implementerar alla komponentmetoder, vanligtvis genom att delegera dem till sina barn
Variation
Som det beskrivs i Design Patterns innefattar mönstret också att inkludera barnmanipuleringsmetoderna i huvudkomponentgränssnittet, inte bara Composite-underklassen. Nyare beskrivningar utelämnar ibland dessa metoder.
Exempel
Följande exempel, skrivet i Java , implementerar en grafikklass, som kan vara antingen en ellips eller en sammansättning av flera grafik. Varje grafik kan skrivas ut. I Backus-Naur form ,
Grafik ::= ellips | GraphicList GraphicList ::= tom | Grafisk grafisk lista
Det kan utökas till att implementera flera andra former (rektangel, etc.) och metoder ( translate , etc.).
Java
importera java.util.List ; importera java.util.ArrayList ; /** "Komponent" */ interface Graphic { //Skriver ut grafiken. public void print (); } /** "Composite" */ class CompositeGraphic implementerar Graphic { //Samling av underordnad grafik. private final List < Graphic > childGraphics = new ArrayList <> (); //Lägger till grafiken till kompositionen. public void add ( Graphic graphic ) { childGraphics . add ( grafik ); } //Skriver ut grafiken. @Override public void print () { for ( Graphic graphic : childGraphics ) { graphic . print (); //Delegation } } } /** "Löv" */ class Ellipse implements Graphic { //Skriver ut grafiken. @Override public void print () { System . ut . println ( "Ellips" ); } } / ** Client */ class CompositeDemo { public static void main ( String [] args ) { //Initialisera fyra ellipser Ellipse ellips1 = new Ellipse (); Ellips ellips2 = ny Ellips (); Ellips ellips3 = ny Ellips (); Ellips ellips4 = ny Ellips (); //Skapar två kompositer som innehåller ellipserna CompositeGraphic compositGraphic2 = new CompositeGraphic ( ); compositGraphic2 . add ( ellips1 ); compositGraphic2 . add ( ellips2 ); compositGraphic2 . add ( ellips3 ); CompositeGraphic compositGraphic3 = ny CompositeGraphic (); compositGraphic3 . add ( ellips4 ); //Skapa ytterligare en grafik som innehåller två grafik CompositeGraphic compositGraphic = new CompositeGraphic (); compositGraphic . add ( compositGraphic2 ); compositGraphic . add ( compositGraphic3 ); //Skriver ut hela grafiken (fyra gånger strängen "Ellipse"). compositGraphic . print (); } }
Se även
externa länkar
- Composite Pattern implementering i Java
- Kompositmönsterbeskrivning från Portland Pattern Repository
- Sammansatt mönster i UML och i LePUS3, ett formellt modelleringsspråk
- Klass::Delegation på CPAN
- "The End of Inheritance: Automatic Run-time Interface Building for Aggregated Objects" av Paul Baranowski
- PerfectJPattern Open Source Project , ger komponentiserad implementering av det sammansatta mönstret i Java
- [1] En beständig Java-baserad implementering
- Komposit designmönster