Prototip (projektni uzorak)

S Vikipedije, slobodne enciklopedije

Prototip projektni uzorak je projektni uzorak kreiranja koji se koristi prilikom razvoja softvera kada se vrsta objekta koji treba kreirati određuje pomoću prototipske instance, koja se klonira da bi se dobio novi objekat. Ovaj projektni uzorak se koristi:

  • da se izbegnu potklase koje kreiraju objekte u klijentskim aplikacijama, kao što je to slučaj kod apstraktne fabrike.
  • da se izbegne kreiranje novih objekata standardnim načinima (npr. korišćenjem ključne reči „new“) što nekad može biti skupa operacija.
  • kada se klase specificiraju u vreme izvršenja, npr. dinamičkim učitavanjem.

Da bi se ovaj projektni uzorak implementirao, deklariše se osnovna klasa koja obezbeđuje čistu virtualnu clone() metodu. Bilo koju klasu kojoj treba mogućnost polimorfnog konstruktora treba izvesti od osnovne klase i implementirati clone() operaciju za nju.

Klijent, umesto da piše kôd koji poziva operator „new“ sa zakucanim imenom klase može da pozive metodu clone() nad prototipom, ili da pozove fabrički metod sa argumentima koji će odrediti željenu konkretnu potklasu za instanciranje, ili da pozive clone() metodu na neki drugi način (koji je obezbedio neki drugi projektni uzorak).

Dijagram klasa[uredi | uredi izvor]

Primeri[uredi | uredi izvor]

Prototip projektni uzorak specificira vrste objekata koji se kreiraju korišćenjem prototipske instance. Prototipovi novih objekata se često kreiraju pre stvarne potrebe za njima, ali u ovim primerima, prototip je pasivan i ne učestvuje u kopiranju samog sebe. Mitoza, tj. deljenje ćelije, čiji su rezultat dve nove identične ćelije je primer prototipa koji igra aktivnu ulogu u kopiranju samog sebe i tako daje dobar primer projektnog uzorka prototipa. Kada se ćelija podeli, dobijaju se dve ćelije sa identičnim genotipima. Drugim rečima, ćelija klonira samu sebe.

Java[uredi | uredi izvor]

/**
 * Klasa prototipa
 */
abstract class PrototypeFactory implements Cloneable {
    public PrototypeFactory clone() throws CloneNotSupportedException {
        // zove Object.clone()
        PrototypeFactory copy = (PrototypeFactory) super.clone();
        // u stvarnoj implementaciji ovog uzorka, ovde mozete zameniti reference na
        // skupa kreiranja kopija koje se nalaze u ovom prototipu.
        return copy;
    }

    abstract void prototypeFactory(int x);

    abstract void printValue();
}

/**
 * Konkretan prototip za kloniranje
 */
class PrototypeImpl extends PrototypeFactory {
    int x;

    public PrototypeImpl(int x) {
        this.x = x;
    }

    @Override
    void prototypeFactory(int x) {
        this.x = x;
    }

    public void printValue() {
        System.out.println("Value : " + x);
    }
}

/**
 * Klijentska klasa
 */
public class PrototypeExample {

    private PrototypeFactory example; // ovde je mogao da bude i Cloneable tip

    public PrototypeExample(PrototypeFactory example) {
        this.example = example;
    }

    public PrototypeFactory makeCopy() throws CloneNotSupportedException {
        return this.example.clone();
    }

    public static void main(String args[]) {
        try {
            PrototypeFactory tempExample = null;
            int num = 1000;
            PrototypeFactory prot = new PrototypeImpl(1000);
            PrototypeExample cm = new PrototypeExample(prot);
            for (int i = 0; i < 10; i++) {
                tempExample = cm.makeCopy();
                tempExample.prototypeFactory(i * num);
                tempExample.printValue();
            }
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

Pajton[uredi | uredi izvor]

import copy
#
# Klasa prototipa
#
class Cookie:
    def __init__(self, name):
        self.name = name
    
    def clone(self):
        return copy.deepcopy(self)
#
# Konkretan prototip za kloniranje
#
class CoconutCookie(Cookie):
    def __init__(self):
        Cookie.__init__(self, 'Coconut')
#
# Klijentska klasa
#
class CookieMachine:
    def __init__(self, cookie):
        self.cookie = cookie
 
    def make_cookie(self):
        return self.cookie.clone()
 
if __name__ == '__main__':
    prot = CoconutCookie()
    cm = CookieMachine(prot)

    for i in xrange(10):
        temp_cookie = cm.make_cookie()


C#[uredi | uredi izvor]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Prototype
{
    class PrototypeExample
    {
        abstract class PrototypeCloning<T> where T : PrototypeCloning<T>
        {
            public T Clone()
            {
                return (T)this.MemberwiseClone();
            }

            public abstract void Print();
            public abstract int X { get; set; }
        }

        class Implementation : PrototypeCloning<Implementation> 
        {
            public Implementation(int x) { X = x; }
            public override void Print()
            {
                Console.WriteLine(X);
            }

            public override int X { get; set; }
        }

        private PrototypeCloning<Implementation> example; 

        PrototypeExample(PrototypeCloning<Implementation> example)
        {
            this.example = example;
        }

        PrototypeCloning<Implementation> MakeCopy()
        {
            return this.example.Clone();
        }

        static void Main(string[] args)
        {
            int num = 1000;
            PrototypeCloning<Implementation> tempExample = null;
            PrototypeCloning<Implementation> prot = new Implementation(num);
            PrototypeExample cm = new PrototypeExample(prot);
            for (int i = 0; i < 10; i++)
            {
                tempExample = cm.MakeCopy();
                tempExample.X = i * num;
                tempExample.Print();
            }
        }
    }
}

Primenljivost[uredi | uredi izvor]

Nekada se projektni uzorci kreiranja preklapaju - ima slučajeva kada je odgovarajuće primeniti samo prototip ili apstraktnu fabriku. U drugim slučajevima, oni se nadopunjuju: apstraktna fabrika može da drži skup prototipova koje klonira i da vraća tako napravljene objekte. Apstraktna fabrika, graditelj i prototip mogu koristiti unikat u okviru njihovih implementacija. Klase apstraktne fabrike se često implementiraju pomoću fabričkih metoda (kreiranje kroz nasleđivanje), ali nekad se mogu implementirati korišćenjem prototipa (kreiranje kroz delegaciju).

Često, početni dizajn projekta počinje sa fabričkom metodom (prostiji, lako se prilagođava, ali dovodi do eksplozije potklasa) i evoluira u apstraktnu fabriku, prototip ili graditelja (fleksibilnije, ali i kompleksnije) kako projektant otkriva gde je potrebno više fleksibilnosti.

Prototip ne zahteva nasleđivanje, ali zahteva operaciju „inicijalizacije“. Fabrička metoda zahteva naslešivanje, ali ne zahteva inicijalizaciju.

Projektima koji dosta koriste projektne uzorke kompozicije ili dekoratera često pomaže prototip.

Po ovome, primenljivost je onda definisana tako da treba koristiti kloniranje (clone() metoda) objekta kada se u vreme izvršenja želi kreirati drugi objekat koji je tačna kopija objekta koji se klonira. Tačna kopija znači da svi članovi novokreiranog objekta moraju biti isti kao u objektu koji se klonira. Da se klasa instancira korišćenjem operatora new, dobio bi se objekat čiji su članovi postavljeni na podrazumevane, inicijalne vrednosti. Na primer, ako se projektuje sistem za obradu bankarskih transakcija, trebalo bi napraviti kopiju objekta koji drži podatke o nalogu, izvršiti transakciju sa njim i zameniti originalni objekat sa izmenjenim objektom. U takvim slučajevima, trebalo bi koristiti clone() umesto new.