GOF設計模式——Prototype模式
一、什麽是Prototype模式?
在編程中,我們可以使用new關鍵字指定類名來生成類的實例,但是有時候也會有不指定類名的前提下生成實例。因為有時候對象種類繁多,無法將它們整合到一個類中;或者,生成實例的過程過於復雜,難以根據類生成實例;又或者,想要將類與框架解耦。這時,為了能夠在不使用類名的情況下生成實例,可以使用Prototype模式,Prototype模式又叫原型模式,專門做一些“復制”的操作。
二、Prototype模式思想
Client負責調用Prototype接口生成實例,具體的實例生成的過程交給ConcretePrototype實現類,那麽在Client調用Prototype這整個過程中都沒有涉及ConcretePrototype類名。
三、具體實例
假設現在要做一個功能,將字符串放入方框中顯示,或者加上下劃線等操作。
1、Manager類
package com.cjs.Prototype;
import java.util.HashMap;
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 product = (Product) showCase.get(protoName);
return product.createClone();
}
}
Manager類定義了兩個方法,一個用於註冊類,另一個是根據關鍵信息創建實例。
2、Product類
package com.cjs.Prototype;
public abstract class Product implements Cloneable {
public abstract void use(String s);
public final Product createClone() {
Product product = null;
try {
product = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
}
}
Product類定義了一個抽象方法use,用於讓子類實現時擁有個性的行為;還有一個被final修飾的createClone方法,用於復制類,生成實例,這裏用到了Template Method模式。
3、UnderlinePen類
package com.cjs.Prototype;
public class UnderlinePen extends 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("");
}
}
4、MessageBox類
package com.cjs.Prototype;
public class MessageBox extends Product {
private char decochar;
public MessageBox(char decochar) {
this.decochar = decochar;
}
@Override
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();
}
}
5、Main類
package com.cjs.Prototype;
public class Main {
public static void main(String[] args) {
Manager manager = new Manager();
UnderlinePen underlinePen = new UnderlinePen(‘~‘);
System.out.println("main underlinePen‘s hashCode = " + underlinePen.hashCode());
MessageBox messageBox1 = new MessageBox(‘*‘);
System.out.println("main messageBox1‘s hashCode = " + messageBox1.hashCode());
MessageBox messageBox2 = new MessageBox(‘/‘);
System.out.println("main messageBox2‘s hashCode = " + messageBox1.hashCode());
manager.register("strong message", underlinePen);
manager.register("warning box", messageBox1);
manager.register("slash box", messageBox2);
Product p1 = manager.create("strong message");
System.out.println("Prototype p1‘s hashCode = " + p1.hashCode());
Product p2 = manager.create("warning box");
System.out.println("Prototype p2‘s hasCode = " + p2.hashCode());
Product p3 = manager.create("slash box");
System.out.println("Prototype p3‘s hasCode = " + p2.hashCode());
p1.use("hello world");
p2.use("hello world");
p3.use("hello world");
}
}
輸出結果:
Main類裏面對於每個生成的實例都打印出它們的hashCode,從Console窗口可以看出,即使是復制出來的實例,它們都不是同一個對象。在整個創建實例的過程中,除了一開始註冊的時候用到了類名,其余的只用到了關鍵字,如“strong message”,“warning box”等,就可以創建對應的實例對象。
四、Prototype的作用
1、對象種類繁多,實現功能類似,使用Prototype模式可以便於源程序的管理,合理減少了類的數量;
2、在難以根據類生成實例的時候,有時候需要創建的類非常復雜,如果經常需要用到此類的對象,那麽每次創建的時候會非常繁瑣,相反,通過實例生成實例的方式會簡單得多。
3、解耦
前面也提過很多次,一旦在某個類文件使用了一個類名來創建實例對象,那麽這個類文件就跟使用的這個類具有高度的耦合性,特別是如果框架也這麽做,那麽這個框架就只適用某些類。
GOF設計模式——Prototype模式