2011. február 5., szombat

Prototípus (Prototype)

Megint a Factory-ból kell kiindulni ám ezúttal prototípusokat lehet gyártani. A cél, hogy előre inicializált típusokat lehessen menet közben készíteni úgy, hogy annak részletkérdéseivel már ne kelljen foglalkozni. A típusokat klónozással kell előállítani, szükség esetén mély másolással. (Amikor a referencia tagokat újra kell kreálni, hogy két objektum ne használja őket közösen). Sokszor előfordul az, hogy bizonyos osztályt prototípusként használunk fel. Ilyenkor általában az "új" típust származtatjuk a régiből és semmit sem változtatunk rajta, csak a konstruktorban inicializáljuk:
class MyObject
{
int size;

public MyObject(int size)
{
this.size = size;
}
}

class MyOtherObject : MyObject
{
public MyOtherObject()
: base(22)
{ }
}
Ezzel tulajdonképpen semmit sem csináltunk, nem fejlesztettük tovább az objektumot, csak létrehoztunk egy prototípus osztályt. Ez főleg akkor válik nehézkessé, amikor ebből kellene 30-40 féle. Többek között az ilyen esetekre jó a Prototípus használata.

Alkalmazhatóság

Akkor használjuk a Prototype mintát, ha rendszernek függetlennek kell lennie a termék létrehozási, összeállítási és megjelenítési módjától; és
  • ha a példányosítandó osztályok futásidőben határozódnak meg, például dinamikus betöltés esetén, vagy
  • el szeretnénk kerülni a termékek osztályhierarchiájával párhuzamos osztályhierarchiájú gyárak építését, vagy
  • amikor az osztályok példányainak csak néhány különböző állapotkombinációja lehet. Kényelmesebb a megfelelő számú prototípust elhelyezni és klónozni, mint példányosítani a megfelelő állapottal.
Struktúra


Résztvevők
  1. Protype: deklarál egy interface-t önmaga klónozásához.
  2. ConcretePrototype: implementál egy műveletet önmaga klónozásához.
  3. Client: új objektumot hoz létre, megkérve a prototípust önmaga klónozására.

Együttműködési információk

A kliens megkéri a a prototípust, hogy klónozza önmagát.

Következmények

A Prototype minta hasonló következményekkel jár mit az Abstract Factory és Builder: elrejti a termék osztályokat a kliens elől, csökkentve a ezzel azon nevek számát, amiket a kliens ismer. Emellett, ezek a minták lehetővé teszik, hogy a kliens módosítás nélkül dolgozzon az alkalmazás-specifikus osztályokkal.

A Prototype minta további előnyei:
  1. Termékek hozzáadása és eltávolítása futásidőben. Új konkrét termékosztály beépítése a rendszerbe, egyszerűen a prototípuspéldány bejegyeztetése a klienssel. Ez valamelyest hatékonyabb, mint a többi létrehozási minta, mert a kliens futásidőben építhet be és távolíthat el prototípusokat.
  2. Új objektumok meghatározása változó értékek mellett. A nagymértékben dinamikus rendszerek lehetővé teszik a új viselkedés definiálását az objektum összetételén keresztül – például az objektum változóinak értéket adva – és nem új osztályokat meghatározva. Ténylegesen a meglévő osztályok példányosításával, és ezek a prototípus kliens-objektumaiként bejegyeztetve adjuk meg. A kliens az új viselkedésmódot a felelősség prototípusra való átruházásával adhatja meg. Ez a tervezési mód lehetőséget ad új „osztályok” létrehozására programozás nélkül. Valójában a prototípus klónozása hasonló egy osztály példányosításához. A Prototype minta nagymértékben csökkenti a rendszer számára szükséges osztályok számát.
  3. Új objektum megadása változó struktúra mellett. Sok alkalmazás részekből és alrészekből építi fel az objektumokat. Kényelmi szempontok miatt, az ilyen alkalmazások lehetővé teszik az összetett, felhasználó által definiált struktúrák példányosítását.
  4. Kevesebb alosztály. A Prototype minta lehetőséget ad a prototípus klónozására, ahelyett, hogy egy gyártó metódust kérne meg új objektum létrehozására. Ezért nincs szükség Creator osztály hierarchiára.
  5. Alkalmazás dinamikus beállítása osztályokkal. Egyes futásidejű környezetek lehetővé teszik az osztályok dinamikus betöltését alkalmazásokba.
A Prototype minta legfőbb felelőssége, hogy mindegyik Prototype alosztálynak implementálnia kell a Clone műveletet, ami bonyolult lehet. Például nehéz, ha az adott osztály már létezik. Clone implementálása akkor is nehéz lehet, ha olyan objektumokat tartalmaznak, amelyek nem támogatják a másolást vagy körkörös hivatkozást tartalmaznak.

Implementációs rész

A Prototype implementációjánál tartsuk szem előtt a következőket:
  1. Prototype menedzser használata. Amikor egy rendszerben a prototípusok száma nem rögzített (tehát dinamikusan létrehozhatóak és megsemmisíthetőek), nyilván kell tartani a rendelkezésre álló prototípusokat. A kliensek maguk nem kezelik a prototípusokat, csak mentik és kiolvassák a nyilvántartóból. Egy kliens elkéri a prototípust a nyilvántartóból, mielőtt klónozná azt. Ezt nyilvántartót hívjuk Prototype menedzsernek. A prototype menedzser egy asszociatív tároló, ami egy adott kulcshoz tartozó prototípust ad vissza. Vannak műveletei a kulcshoz tartozó prototípus bejegyzésére és a bejegyzés érvénytelenítésére. A kliensek megváltoztathatják a nyilvántartót és tallózhatják azt futásidőben. Ez lehetővé teszi a klienseknek, hogy a rendszer leltárát kódírás nélkül felvegyék.
  2. A Clone művelet implementálása. A Prototype minta legnehezebb része a Clone művelet helyes implementálása. Ez kiváltképp bonyolult amikor az objektumstruktúra körkörös hivatkozásokat tartalmaz. Ha a rendszerben lévő objektumok rendelkeznek Save és Load műveletekkel, akkor ezek használhatóak a Clone alapértelmezett implementálásához, egyszerűen csak menteni kell az objektumot majd azonnal visszatölteni. A Save művelet menti az objektumot egy puffermemóriába, a Load egy másolatot hoz létre, rekonstruálva a objektumot a pufferből.
  3. Klónok inicializálása. Amíg néhány kliens tökéletesen elégedett a klónnal, ahogy van, mások az általuk választott értékkel akarják inicializálni néhány vagy az összes belső állapotát. Általában ezeket az értékeket nem lehet átadni a Clone műveletben, mert számuk prototípus-osztályonként változik. Néhány prototípusnak szüksége lehet több inicializáló paraméterre; másoknak egyre sincs szükségük. A Clone műveletben történő paraméterátadás eleve kizárná egy egységes klónozó interfész használatát. Lehetséges, hogy a prototípus osztályok már definiálnak műveleteket az állapot kulcsrészeinek (újra) beállítására. Ha ez van, akkor a kliensek ezeket a műveleteket használhatják azonnal klónozás után. Ha nincs, akkor lehet nekünk kell az Initialize műveletet bevezetni, amely argumentumként kapja meg az inicializáló paramétereket és ennek megfelelően állítja be a klón belső állapotát.
Minta kód
// Prototype pattern
using System;
using System.Collections.Generic;

namespace Prototype
{
///
/// MainApp startup class for Real-World
/// Prototype Design Pattern.
///

class MainApp
{
///
/// Entry point into console application.
///

static void Main()
{
ColorManager colormanager = new ColorManager();

// Initialize with standard colors
colormanager["red"] = new Color(255, 0, 0);
colormanager["green"] = new Color(0, 255, 0);
colormanager["blue"] = new Color(0, 0, 255);

// User adds personalized colors
colormanager["angry"] = new Color(255, 54, 0);
colormanager["peace"] = new Color(128, 211, 128);
colormanager["flame"] = new Color(211, 34, 20);

// User clones selected colors
Color color1 = colormanager["red"].Clone() as Color;
Color color2 = colormanager["peace"].Clone() as Color;
Color color3 = colormanager["flame"].Clone() as Color;

// Wait for user
Console.ReadKey();
}
}

///
/// The 'Prototype' abstract class
///

abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}

///
/// The 'ConcretePrototype' class
///

class Color : ColorPrototype
{
private int _red;
private int _green;
private int _blue;

// Constructor
public Color(int red, int green, int blue)
{
this._red = red;
this._green = green;
this._blue = blue;
}

// Create a shallow copy
public override ColorPrototype Clone()
{
Console.WriteLine(
"Cloning color RGB: {0,3},{1,3},{2,3}", _red, _green, _blue);

return this.MemberwiseClone() as ColorPrototype;
}
}

///
/// Prototype manager
///

class ColorManager
{
private Dictionary _colors =
new Dictionary();

// Indexer
public ColorPrototype this[string key]
{
get { return _colors[key]; }
set { _colors.Add(key, value); }
}
}
}
Ismert felhasználás
  • Eszköztáraknál
  • Alapvető plug-in mechanizmusoknál
  • EJB/COM Szervereknél
Kapcsolódó minták

A Prototype és az Abstract Factory bizonyos tekintetben konkurens minták. Azonban használhatóak együtt is. Az Abstract Factory tárolhat egy olyan prototípus halmazt, amelyet klónozni akarunk, és a termék objektumokat adjuk vissza.

Felhasznált anyagok

0 megjegyzés :

Megjegyzés küldése