Összetétel programtervezési minta
A számítógépes programozásban az összetétel programtervezési minta vagy összetétel tervezési minta egy strukturális programtervezési minta. Az összetétel minta az írja le, hogy az objektumok egy csoportját ugyanúgy kell kezelni, mint egy adott objektum példányait külön-külön. Az összetétel itt arra utal, hogy fa struktúrába szervezzünk objektumokat így reprezentálva a rész-egész hierarchiákat. Az összetétel minta lehetővé teszi, hogy a kliensek az önálló objektumokat és összetételeket egységes módon kezeljék.[1]
Motiváció
Amikor fa struktúrájú adatokkal foglalkozunk, a fejlesztőnek gyakran különbséget kell tudni tennie a levél elemeket az egyéb csomópontoktól. Ez a kódot még komplexebbé és hibára hajlamossá teszi. A megoldás egy interfész, amely lehetővé teszi a komplex és primitív objektumok egységes kezelését. Az objektumorientált programozásban az összetétel egy objektum tervezési mód, hasonló objektumok 1 vagy több kapcsolata, mindegyik hasonló funkcionalitással ellátva. Ezt úgy hívják, hogy "has-a" kapcsolat objektumok között.[2] A kulcs fogalom az, hogy hogyan lehet manipulálni az objektum egy példányát ugyanúgy, mintha az objektum egy egész csoportját manipulálnánk. Azoknak a műveleteknek, melyeket végre lehet hajtani az összes összetett objektumon gyakran van egy legkisebb közös nevező kapcsolata. Például ha a képernyőn egy rendszert definiálunk csoportosított alakzatok képeihez, hasznos lenne, ha definiálnánk átméretezését az alakzatok egy csoportjára, úgy hogy ugyanaz a hatásuk (bizonyos értelemben) legyen mintha csak egy alakzatot kellett volna átméretezni.
Használata
Az összetételt akkor célszerű használni, ha a kliensek figyelmen kívül hagyják a különbséget az objektumok összetétele és az önálló objektumok között.[1] Ha fejlesztők úgy találják, hogy több objektumot akarnak azonos módon használni és gyakran van majdnem azonos kódjuk az egyes elemek kezelésére, akkor az összetétel egy jó választás; kevésbé komplex ebben az esetben kezelni az egyszerű és összetett objektumokat homogén módon.
Struktúra
- Komponens
- absztrakció az összes összetevőhöz, beleértve az összetettet is
- az objektumok számára meghatározza az interfészt az összetételben
- (nem kötelező) meghatározza az interfészt egy komponens szülőjének eléréséhez a rekurzív struktúrában, és megvalósítja azt, amennyiben szükséges
- Levél elem
- reprezentálja a levél objektumokat az összetételben
- megvalósítja az összes komponens metódust
- Összetétel
- reprezentál egy összetett komponenst (gyerekekkel rendelkező komponens)
- megvalósítja a gyerekek kezeléséhez szükséges metódusokat
- megvalósítja az összes komponens metódust, általában a gyerekekhez való delegálással
Variációk
Mint ahogy azt leírtuk a tervezési mintákban a minta szintén magába foglalja a gyerek kezeléséhez szükséges metódusokat a fő komponens interfészében, nem csak az összetétel alosztályaiban. Újabb leírásokban néha kihagyják ezeket a metódusokat.[3]
Példák
A következő példa Java nyelven íródott, amely egy grafikus osztályt implementál, amely lehet egy ellipszis vagy a más grafikus elemek összetétele. Minden grafika nyomtatható. A Backus-Naur-formával:
Graphic = ellipse | GraphicList GraphicList = empty | Graphic GraphicList
Ki lehet terjeszteni, hogy számos más alakot (négyzet stb.) ill. metódust (forgatást, stb.) implementáljon.
Java
/** "Component" */
interface Graphic {
//Prints the graphic.
public void print();
}
/** "Composite" */
import java.util.List;
import java.util.ArrayList;
class CompositeGraphic implements Graphic {
//Collection of child graphics.
private List<Graphic> childGraphics = new ArrayList<Graphic>();
//Prints the graphic.
public void print() {
for (Graphic graphic : childGraphics) {
graphic.print();
}
}
//Adds the graphic to the composition.
public void add(Graphic graphic) {
childGraphics.add(graphic);
}
//Removes the graphic from the composition.
public void remove(Graphic graphic) {
childGraphics.remove(graphic);
}
}
/** "Leaf" */
class Ellipse implements Graphic {
//Prints the graphic.
public void print() {
System.out.println("Ellipse");
}
}
/** Client */
public class Program {
public static void main(String[] args) {
//Initialize four ellipses
Ellipse ellipse1 = new Ellipse();
Ellipse ellipse2 = new Ellipse();
Ellipse ellipse3 = new Ellipse();
Ellipse ellipse4 = new Ellipse();
//Initialize three composite graphics
CompositeGraphic graphic = new CompositeGraphic();
CompositeGraphic graphic1 = new CompositeGraphic();
CompositeGraphic graphic2 = new CompositeGraphic();
//Composes the graphics
graphic1.add(ellipse1);
graphic1.add(ellipse2);
graphic1.add(ellipse3);
graphic2.add(ellipse4);
graphic.add(graphic1);
graphic.add(graphic2);
//Prints the complete graphic (four times the string "Ellipse").
graphic.print();
}
}
C#
A következő grafikai példa C#-en íródott.
namespace CompositePattern
{
using System;
using System.Collections.Generic;
using System.Linq;
//Client
class Program
{
static void Main(string[] args)
{
// initialize variables
var compositeGraphic = new CompositeGraphic();
var compositeGraphic1 = new CompositeGraphic();
var compositeGraphic2 = new CompositeGraphic();
//Add 1 Graphic to compositeGraphic1
compositeGraphic1.Add(new Ellipse());
//Add 2 Graphic to compositeGraphic2
compositeGraphic2.AddRange(new Ellipse(),
new Ellipse());
/*Add 1 Graphic, compositeGraphic1, and
compositeGraphic2 to compositeGraphic */
compositeGraphic.AddRange(new Ellipse(),
compositeGraphic1,
compositeGraphic2);
/*Prints the complete graphic
(four times the string "Ellipse").*/
compositeGraphic.Print();
Console.ReadLine();
}
}
//Component
public interface IGraphic
{
void Print();
}
//Leaf
public class Ellipse : IGraphic
{
//Prints the graphic
public void Print()
{
Console.WriteLine("Ellipse");
}
}
//Composite
public class CompositeGraphic : IGraphic
{
//Collection of Graphics.
private readonly List<IGraphic> graphics;
//Constructor
public CompositeGraphic()
{
//initialize generic Collection(Composition)
graphics = new List<IGraphic>();
}
//Adds the graphic to the composition
public void Add(IGraphic graphic)
{
graphics.Add(graphic);
}
//Adds multiple graphics to the composition
public void AddRange(params IGraphic[] graphic)
{
graphics.AddRange(graphic);
}
//Removes the graphic from the composition
public void Delete(IGraphic graphic)
{
graphics.Remove(graphic);
}
//Prints the graphic.
public void Print()
{
foreach (var childGraphic in graphics)
{
childGraphic.Print();
}
}
}
}
Egy egyszerű példa
//IVSR: Composite example
/// Treats elements as composition of one or more elements, so that components
/// can be separated between one another
public interface IComposite
{
void CompositeMethod();
}
public class LeafComposite :IComposite
{
#region IComposite Members
public void CompositeMethod()
{
//To Do something
}
#endregion
}
/// Elements from IComposite can be separated from others
public class NormalComposite : IComposite
{
#region IComposite Members
public void CompositeMethod()
{
//To Do Something
}
#endregion
public void DoSomethingMore()
{
//Do Something more .
}
}
Kapcsolódó szócikkek
További információk
- Composite pattern description from the Portland Pattern Repository
- Composite pattern in UML and in LePUS3, a formal modelling language
- Class::Delegation on CPAN
- "The End of Inheritance: Automatic Run-time Interface Building for Aggregated Objects" by Paul Baranowski
- PerfectJPattern Open Source Project, Provides componentized implementation of the Composite Pattern in Java
- [1] A persistent Java-based implementation
- Composite Design Pattern
- Composite Design Pattern implementation example
Jegyzetek
- ↑ a b Gamma, Erich. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 395. o. (1995). ISBN 0-201-63361-2
- ↑ Scott Walters. Perl Design Patterns Book (2004) Archiválva 2016. március 8-i dátummal a Wayback Machine-ben
- ↑ Geary, David: A look at the Composite design pattern, 2002. szeptember 13. [2013. október 31-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. február 17.)
Fordítás
Ez a szócikk részben vagy egészben a Composite pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.