Jeśli moja strona Ci pomogła, i chcesz aby była bardziej rozwijana, wesprzyj mnie
buy me a coffee
I. Wzorce kreacyjne
II. Wzorce strukturalne
III. Wzorce czynnościowe
|
Prototyp - Prototype - wzorzec projektowy (design pattern) - java
1. Cel:
Uzyskać szybkie tworzenie obietku z domyślnymi wartościami,
aby nie było kosztowne użycie słowa kluczego new i przypisania wartości domyślnych.
2. Problem:
Mamy obiekt i chcemy stworzyć jego kopię wraz z domyślnymi wartościami,
więc musisz stworzyć nowy obiekt i przypisać mu wszystkie potrzebne pola.
3. Rozwiązanie:
Użycie interface-u Cloneable oraz metody clone do stworzenia kopii obiektu.
Prototyp odnosi się do obiektów implementującym wspólny interface
4. Diagram klas klasy prototyp:

5. Implementacja:
a) Implementacja wzorca Prototyp połączona z wzorcem projektowym singleton:
Abstrakcyjna klasa która będzie dziedziczona przez klasy właściwe.
package pl.edu.java.designpatterns.prototype;
public abstract class Element implements Cloneable {
private String tytul;
private double cena;
private String url;
public Element() {
}
public Element(String tytul,
double cena,
String url) {
this.tytul = tytul;
this.cena = cena;
this.url = url;
}
public String getTytul() {
return tytul;
}
public void setTytul(String tytul) {
this.tytul = tytul;
}
public double getCena() {
return cena;
}
public void setCena(double cena) {
this.cena = cena;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Element clone() {
try {
return (Element) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
Klasa Film która implementuje Element
package pl.edu.java.designpatterns.prototype;
public class Film extends Element {
int czasFilmu;
public Film() {
}
public Film(int czasFilmu,
String tytul,
double cena,
String url) {
super(tytul, cena, url);
this.czasFilmu = czasFilmu;
}
public int getCzasFilmu() {
return czasFilmu;
}
public void setCzasFilmu(int czasFilmu) {
this.czasFilmu = czasFilmu;
}
}
Klasa Ksiazka która implementuje Element
package pl.edu.java.designpatterns.prototype;
public class Ksiazka extends Element {
int liczbaStron;
public Ksiazka() {
}
public Ksiazka(int liczbaStron,
String tytul,
double cena,
String url) {
super(tytul, cena, url);
this.liczbaStron = liczbaStron;
}
public int getLiczbaStron() {
return liczbaStron;
}
public void setLiczbaStron(int liczbaStron) {
this.liczbaStron = liczbaStron;
}
}
Obsługa metody clone dla wzorca prototypu
package pl.edu.java.designpatterns.prototype;
import java.util.HashMap;
import java.util.Map;
public class Rejestr {
private static Rejestr rejestr = new Rejestr();
private Map<String, Element> elementy = new HashMap<>();
private Rejestr() {
zaladujElementy();
}
public static Element stworzElement(String element) {
return rejestr.elementy.get(element).clone();
}
private void zaladujElementy() {
Ksiazka ksiazka = new Ksiazka();
ksiazka.setLiczbaStron(200);
ksiazka.setCena(34.99);
ksiazka.setTytul("Banda czworga");
ksiazka.setUrl("java.edu.pl/book/3.prototype.php");
elementy.put("ksiazka", ksiazka);
Film film = new Film();
film.setCzasFilmu(130);
film.setTytul("Design patterns - prototype");
film.setCena(49.99);
film.setUrl("java.edu.pl/movies/3.prototype.php");
elementy.put("film", film);
}
}
Klasa prezentująca wzorzec:
package pl.edu.java.designpatterns.prototype;
public class PrototypeTest {
public static void main(String[] args) {
Ksiazka ksiazka = (Ksiazka) Rejestr.stworzElement("ksiazka");
Film film = (Film) Rejestr.stworzElement("film");
System.out.println(ksiazka.getTytul() + " id:" + ksiazka.hashCode());
Ksiazka ksiazkaClone = (Ksiazka) Rejestr.stworzElement("ksiazka");
System.out.println(ksiazkaClone.getTytul() + " id:" + ksiazkaClone.hashCode());
}
}
Wynik:
Banda czworga id:1163157884
Banda czworga id:1956725890
b) implementując metodę clone można to zrobić na dwa sposoby:
- płytkie klonowanie
- głębkie klonowanie
Trzeba uważać czy na pewno chcemy płytkiego klonowania, może to stworzyć problemy:
package pl.edu.java.designpatterns.prototype;
public class Rekord {
}
package pl.edu.java.designpatterns.prototype;
import java.util.List;
public class Statement implements Cloneable {
String query;
List<String> parametr;
Rekord rekord;
public Statement(String query, List<String> parametr, Rekord rekord) {
this.query = query;
this.parametr = parametr;
this.rekord = rekord;
}
public String getQuery() {
return query;
}
public List<String> getParametr() {
return parametr;
}
public Rekord getRekord() {
return rekord;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
I klasa testowa naszego przypadku.
import java.util.ArrayList; import java.util.List; public class StatementTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("NAME"); list.add("LASTNAME"); Statement stmt = new Statement("SELECT * FROM USERS", list, new Rekord()); System.out.println("stmt_Id:" + stmt.hashCode() +" ,listSize=" + stmt.parametr.size() + " Rekord_Id: " + stmt.getRekord().hashCode()); Statement stmtClone = (Statement)stmt.clone(); stmtClone.getParametr().add("CITY"); System.out.println("stmtClone_Id:" + stmtClone.hashCode() +" ,listSize=" + stmtClone.parametr.size() + " Rekord_Id: " + stmtClone.getRekord().hashCode()); System.out.println("stmt_Id:" + stmt.hashCode() +" ,listSize=" + stmt.parametr.size() + " Rekord_Id: " + stmt.getRekord().hashCode()); } }
Wynik:
stmt_Id:1163157884 ,listSize=2 Rekord_Id: 1956725890
stmtClone_Id:356573597 ,listSize=3 Rekord_Id: 1956725890
stmt_Id:1163157884 ,listSize=3 Rekord_Id: 1956725890
Jest to płytkie kopiowanie przez co obiekty takie jak List<> i Rekord są tym samym obiektem po klonowaniu.
Zmiana elemtnów List<> powoduje że w obydwu obiektach stmt i stmtClone się zmieni
Gdy zrobimy operacje na obiekcie Rekord, również w dwóch miejscach będą widzoczne zmiany
Dlatego należało by stworzyć nową List<> listę obiektów oraz kolejny klon obiektu Rekord. Czyli głębokie klonowanie
6. Zastosowanie w kodzie java:
java.lang.Object#clone() - klasa musi implementować interface: java.lang.Cloneable
|