在java中我們經常使用new關鍵字指定類名來生成實例。像這樣使用new來生成實例時,是必須要指定類名的。但是,在開發過程中,有時也會有“在不指定類名的前提下生成實例”的需求。例如一下幾種情況,就不能根據類來生成實例,而要根據現有的實例來生成新的實例。
(1)對象種類繁多,無法將他們整合到一個類中時
第一種情況是需要處理的對象太多,將他們分別作爲一個類,必須要編寫多個類文件。
(2)難以根據類生成實例時
第二種情況是生成實例的過程太過複雜,很難根據類來生成實例。例如,我們假設這裏有一個實例,即表示用戶在圖形編輯器中使用鼠標製作出圖形的實例。想在程序中創建這樣的實例是非常困難到的。通常,在想生成一個和之前用戶通過操作所創建出的實例完全一樣的實例的時候,我們先阿靜用戶通過操作所創建出的實例保存起來,然後在需要時通過複製來生成實例。
(3)想解耦框架與生成的實例時
第三種情況是想要讓生成的實例的框架不依賴於具體的類。這時,不指定類名來生成示實例,而要先“註冊”一個“原型”實例,然後通過複製該實例來生成實例。
實例程序
package framework;
/*
* Product接口是複製功能的接口。該 接口繼承了java.lang.cloneable接口。
* 該接口類的實例可以地哦啊用clone方法自動複製實例即可。
* use方法是用於“使用”的方法。具體怎麼使用,交給子類去實現。
* createClone方法用於複製實例*/
public interface Product extends Cloneable{
public abstract void use(String s);
public abstract Product createClone();
}
package framework;
import java.util.*;
/*
* Manager類使用Product接口來複制實例。
* showcase字段是java.util.HashMap類型,它保存了實例的“名字”和“實例”之間
* 的對應關係。
* register方法會接收到一組“名字”和“Product接口”註冊到showcase中。
* 我們還無法知道Product類型的proto具體是什麼,但是它肯定實現了Product接口。
* 也就是說可以調用它的use接口和createClone接口。
* 注意在Product接口和Manager類的代碼中完全沒有出現MessageBox類
* 和UnderlinePen類的名字,也就意味着我們可以獨立地修改Product和Manager類
* 不受另外兩個類的影響。這非常重要,因爲一旦使用了別的類名,就意味着該類與其他緊密地耦合在了一起。
* 在這裏僅使用了Product這個接口名,也就是說,Product成爲了連接Manaer類和
* 其他具體類之間的橋樑*/
public class Manager {
private HashMap showcase=new HashMap();
public void register(String name,Product proto) {
showcase.put(name, proto);
}
public Product create(String protoname) {
Product p=(Product) showcase.get(protoname);
return p.createClone();
}
}
package Implement;
import framework.*;
/*
* 該類實現了Product接口。
* decochar字段中保存的是像裝飾方框那樣環繞着字符串的字符。
* use方法會使用decochar字段中保存的字符把要顯示的字符串框起來。
* createClone方法用於複製自己。它內部所調用的clone方法是java語言中的特定方法,
* 用於複製自己。在進行復制時,原來實例中的字段的值也會被複制到新的實例中。
* 我們之所以可以調用clone方法進行復制,僅僅是因爲該類實現了java.lang.Cloneable接口。
* 如果沒有實現這個接口,在運行過程中就會拋出異常。
* 此處實現了Product接口,Product接口又繼承了cloneable接口,因此程序不會拋出異常。
* 對於Product接口來說,java.lang.Cloneable接口知識起到告訴程序可以調用clone方法的作用,
* 它自身並沒有定義任何的方法。
* 只有類自己(或者子類)能夠調用clone方法。當其他類要求賦值實例時,必須要先調用
* createclone方法,然後該方法內部再調用clone方法纔可以。*/
public class MessageBox implements Product{
private char decochar;
public MessageBox(char decochar) {
this.decochar=decochar;
}
public void use(String s) {
int length=s.getBytes().length;
for(int i=0;i<length+4;i++) {
System.out.print(decochar);
}
System.out.println("");
System.out.println(decochar+" "+s+" "+decochar);
for(int i=0;i<length+4;i++) {
System.out.print(decochar);
}
System.out.println("");
}
@Override
public Product createClone() {
Product p=null;
try {
p=(Product) clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return p;
}
}
package Implement;
import framework.*;
/*
* UnderlinePen類和MessageBox類幾乎完全一樣,
* 不同的是underlinePen在字符串底下畫下劃線*/
public class UnderlinePen implements Product{
private char ulchar;
public UnderlinePen(char ulchar) {
this.ulchar=ulchar;
}
@Override
public void use(String s) {
int length=s.getBytes().length;
System.out.println("\""+s+"\"");
System.out.print(" ");
for(int i=0;i<length;i++) {
System.out.print(ulchar);
}
System.out.println("");
}
@Override
public Product createClone() {
Product p=null;
try {
p=(Product) clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return p;
}
}
import Implement.MessageBox;
import Implement.UnderlinePen;
import framework.*;
/*
* Main類首先生成了Manager類實例。
* 接着,在Manager實例中註冊UnderlinePen的實例和MessageBox的實例*/
public class Main {
public static void main(String[] args) {
//準備
Manager manager=new Manager();
UnderlinePen upen=new UnderlinePen('~');
MessageBox mbox=new MessageBox('*');
MessageBox sbox=new MessageBox('/');
manager.register("strong message", upen);
manager.register("warning box", mbox);
manager.register("slash box", sbox);
//生成
Product p1=manager.create("strong message");
p1.use("Hello World");
Product p2=manager.create("warning box");
p2.use("Hello World");
Product p3=manager.create("slash box");
p3.use("Hello World");
}
}
Prototype模式中的登場角色
Prototype(原型)
Product角色負責定義用於複製現有實例生成新的實例的方法。在示例程序中,由Product接口扮演此角色。
ConcretePrototype(具體原型)
ConcretePrototype角色負責實現複製現有實例並生成新的實例的方法。在示例程序中MessageBox和UnderlinPen類扮演此角色。
Client(使用者)
Client角色負責使用複製實例的方法來生成新的實例。在示例程序中,Manager類扮演此角色。