Prototípus programtervezési minta

A Wikipédiából, a szabad enciklopédiából

A prototípus programtervezési minta a szoftverfejlesztésben egy létrehozási programtervezési minta.

Szerkezete[szerkesztés]

UML class diagram describing the prototype design pattern

Sekély és mély klónozás[szerkesztés]

A minta lényege a klónozás, azaz az eredeti objektummal megegyező új példány létrehozása. Az egyszerű értékadás erre nem alkalmas, mivel az csak az objektum hivatkozását másolja le, melynek eredményeképpen az eredeti példány és másolata ugyanoda hivatkozik. Két típust különböztetünk meg, a sekély és a mély klónozást. A sekély klónozás esetében az osztály által hivatkozott objektumokat ugyanúgy másoljuk, mint elemi típusú tulajdonságait. A mély klónozásnál az osztály által hivatkozott objektumokat is klónozzuk.

Példa C# nyelven:

class Ember {
	private String név;
	private Ember[] barátok;
	public Ember DeepCopy() {
		Ember clone = new Ember();
		clone.név = név;
		clone.barátok = (Ember[]) barátok.Clone();
		return clone;
	}
	public Ember ShallowCopy() {
		Ember clone = new Ember();
		clone.név = név;
		clone.barátok = barátok;
		return clone;
	}
	public Ember ShallowCopy2() {
		return (Ember) MemberwiseClone();
	}
}

A sekély klónozást a C# nyelv a MemberwiseClone() metódussal segíti, ami az Object osztály része, így minden osztály örökli. Ezért tudtunk a sekély klónozásra két verziót adni a fenti példában.

Ökölszabályok[szerkesztés]

A létrehozási minták gyakran átfedik, máskor kiegészítik egymást. Például vannak esetek, amikor értelme van a prototípusnak és az absztrakt gyártónak is. Az absztrakt gyártó máskor prototípusokat tárolhat, és azok klónozásával hozhatja létre a terméket (GoF, 126). Az absztrakt gyártó, az építő és a prototípus használhat egykéket az implementációjukhoz (GoF, 81, 134). Az absztrakt gyártókat gyakran gyártó metódusok valósítják meg (létrehozás örökléssel), de lehetnek delegáltak is (prototípusokkal) (GoF, 95).

A tervek eleinte gyakran gyártó metódust tartalmaznak, amit ha kell, lecserélnek absztrakt gyártóra, prototípusra, építőre (GoF, 136).

A prototípus nem igényel öröklődést, de inicializációt igen. A gyártó metódus nem igényel inicializációt, de öröklődést igen (GoF, 116).

A sok összetétel és díszítő mintát használó tervek számára gyakran előnyös a prototípus is (GoF, 126).

Ha valódi másolatot szeretnénk az objektumról, akkor használjunk klónozást. A másolat azt jelenti, hogy nem ugyanaz az objektum, de olyan, mint az eredeti. Ha az objektum még új, tehát még nem végeztünk rajta állapotváltoztató műveletet, akkor hívhatunk konstruktort is, megfelelő paraméterekkel, de ez többszálú környezeten ellenjavallt. Az atomi tulajdonság biztosítására is hasznos a klón, mivel a műveleteket a klónon végezzük, és csak sikeres esetben cseréljük le az eredetit a másolatra, amin immár az újabb műveletek is el vannak végezve. Tipikus példa a bankszámla.

Szemléltetés[szerkesztés]

Az alábbi kódban egy autógyár osztályhierarchiáján keresztül szemléltetjük a technikát. Az autógyárnak osztályhierarchiájának ki kell tudnia szolgálni mind a teherautó, mind pedig a sportkocsigyártást. A forráskódban a sekély klónozásra látunk példát, kétféle módszerrel. Ha a MemberwiseClone() metódust használjuk, akkor elegendő az ősosztályban megírni a Clone() metódust. Ha nem, akkor minden alosztályban megvalósítandó.

C# forráskód[szerkesztés]

using System;
namespace ConsoleApplication63 {
	public abstract class Gépkocsi: ICloneable {
		private string _Tipus;
		public string Tipus {
			get {
				return _Tipus;
			}
			set {
				_Tipus = value;
			}
		}
		private int _UtasokSzama;
		public int UtasokSzama {
			get {
				return _UtasokSzama;
			}
			set {
				_UtasokSzama = value;
			}
		}
		private double _TankMeret;
		public double TankMeret {
			get {
				return _TankMeret;
			}
			set {
				_TankMeret = value;
			}
		}
		private string _Szin;
		public string Szin {
			get {
				return _Szin;
			}
			set {
				_Szin = value;
			}
		}
		public Gépkocsi(string tipus, int utasokszama, double tankmeret) {
			this.Tipus = tipus;
			this._UtasokSzama = utasokszama;
			this._TankMeret = tankmeret;
		}
		public object Clone() {
			return this.MemberwiseClone();
		}
		/*
                public virtual object Clone()
                {
                        Gépkocsi uj = new Gépkocsi(Tipus, UtasokSzama, TankMeret);
                        uj.Szin = Szin;
                        return uj;
                }*/
		public override string ToString() {
			return Tipus + " " + UtasokSzama + " " + TankMeret + " " + Szin;
		}
	}
	public class Versenyautó: Gépkocsi {
		private int _Vegsebesseg;
		public int Vegsebesseg {
			get {
				return _Vegsebesseg;
			}
			set {
				_Vegsebesseg = value;
			}
		}
		public Versenyautó (string t, int u, double tm, int vegsebesseg): base(t, u, tm) {
			this.Vegsebesseg = vegsebesseg;
		}
		/*
                public override object Clone()
                {
                        Versenyautó uj =
                        new Versenyautó(Tipus, UtasokSzama, TankMeret, Vegsebesseg);
                        uj.Szin = Szin;
                        return uj;
                }*/
		public override string ToString() {
			return base.ToString() + " " + Vegsebesseg;
		}
	}
	public class Teherautó: Gépkocsi {
		private double _Teherbiras;
		public double Teherbiras {
			get {
				return _Teherbiras;
			}
			set {
				_Teherbiras = value;
			}
		}
		public Teherautó (string t, int u, double tm, double teherbiras): base(t, u, tm) {
			this.Teherbiras = teherbiras;
		}
		/*
                 public override object Clone()
                 {
                        Teherautó uj =
                        new Teherautó(Tipus, UtasokSzama, TankMeret, Teherbiras);
                        uj.Szin = Szin;
                        return uj;
                 }*/
		public override string ToString() {
			return base.ToString() + " " + Teherbiras;
		}
	}
	public class Gyar {
		public Gépkocsi[] sorozatgyartas(Gépkocsi g, string sz, int db) {
			Gépkocsi[] temp = new Gépkocsi[db];
			for (int i = 0; i < db; i++) {
				temp[i] = (Gépkocsi) g.Clone();
				temp[i].Szin = sz;
			}
			return temp;
		}
	}
	class Program105 {
		static void Main(string[] args) {
			//a versenyautó és a teherautó prototípus létrehozása
			Gépkocsi prototipus1 = new Versenyautó ("Aston Martin", 4, 180, 220);
			Gépkocsi prototipus2 = new Teherautó ("Csepel", 3, 200, 1000);
			Gyar gyartosor = new Gyar();
			// legyárt 10 piros versenyautót
			Gépkocsi[] vk = gyartosor.sorozatgyartas(prototipus1, "Piros", 10);
			foreach(Versenyautóv in vk) {
				Console.WriteLine(v);
			}
			// legyárt 20 szürke teherautót
			Gépkocsi[] tk = gyartosor.sorozatgyartas(prototipus2, "Szürke", 20);
			foreach(Teherautót in tk) {
				Console.WriteLine(t);
			}
			Console.ReadLine();
		}
	}
}

Java példa[szerkesztés]

Az alábbi kód objektumokat készít prototípus alapján.

public abstract class Prototype {
    public abstract Prototype clone();
}
    
public class ConcretePrototype1 extends Prototype {
    @Override
    public Prototype clone() {
        return super.clone();
    }
}

public class ConcretePrototype2 extends Prototype {
    @Override
    public Prototype clone() {
        return super.clone();
    }
}

Források[szerkesztés]

  • Dr. Kusper Gábor és Dr. Radványi Tibor: Jegyzet a projekt labor című tárgyhoz (PDF). Eszterházy Károly Főiskola Matematikai és Informatikai Intézet. (Hozzáférés: 2015. április 6.)
  • Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley (1994). ISBN 0-201-63361-2 

Fordítás[szerkesztés]

Ez a szócikk részben vagy egészben a Prototype pattern című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel.