1. 概述
原型(Prototype)设计模式用于处理“需要在不指定类名的前提下生成实例的情况”,它是通过实例原型,实例模型来生成新的实例。
在如下情况下我们就不能根据类来生成实例,而要根据现有的实例来生成新的实例:
1. 对象种类繁多,无法将它们整合到一个类中。
2. 难以根据类生成实例时:在想生成一个和之前用户通过操作所创建的实例完全一样的实例的时候,我们会事先将用户通过操作所创建出的实例保存起来,然后在需要的时候通过复制生成新的实例。
3. 想解耦框架与生成实例时:想让生成实例的框架不依赖于具体的类。这时不能根据具体的类名来生成新的实例,要实现“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。
2. 代码示例
在框架(framework)包中创建一个使用者类,一个原型类。
原型要有具体的实现类,这里以Product作为原型类,User类作为使用者,Product类有两个具体的原型,类Product01和Product02。
原型类Product.java,原型类需要实现Cloneable接口,Cloneable 接口是一个标识接口,实现了这个接口之后才可以调用Object类的clone方法,浅拷贝和深拷贝可参考:传送门。Product.java代码如下所示:
package prototype.framework;
public interface Product extends Cloneable{
public void use(String s);
public Product createClone();
}
使用者类User.java ,使用者类中要有一个HashMap成员变量来存储已经创建的实例原型,如 public HashMap products = new HashMap(); register(String name, Product proto) ,该方法用于注册原型,public Product create(String protonName),该方法用于拷贝对应的实例原型。
package prototype.framework;
import java.util.HashMap;
public class User {
// 存储已经创建的实例原型
public HashMap products = new HashMap();
// 用于注册原型
public void register(String name, Product proto) {
products.put(name, proto);
}
// 拷贝对应的实例原型
public Product create(String protonName) {
Product p = (Product)products.get(protonName);
return p.createClone();
}
}
两个具体的原型,类Product01和Product02:
Product01.java :
package prototype;
import prototype.framework.Product;
public class Product01 implements Product {
private char decoChar;
public Product01(char decoChar) {
this.decoChar = decoChar;
}
/**
* 使用decoChar包围 字符串s 并打印输出
* @param s
*/
@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("");
}
@Override
public Product createClone() {
Product p = null;
try {
p = (Product)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
Product02.java :
package prototype;
import prototype.framework.Product;
public class Product02 implements Product {
private char ulChar;
public Product02(char ulChar) {
this.ulChar = ulChar;
}
/**
* 使用ulChar 在 s下边放上下划线
* @param s
*/
@Override
public void use(String s) {
int length = s.getBytes().length;
System.out.println(ulChar + " " + s + " " + ulChar);
for (int i=0; i<length+4; i++) {
System.out.print(ulChar);
}
System.out.println("");
}
@Override
public Product createClone() {
Product p = null;
try {
p = (Product)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
测试类test.java,创建使用者、生成原型实例、注册原型实例 、根据原型实例生成实例。
package prototype;
import prototype.framework.Product;
import prototype.framework.User;
public class test {
public static void main(String args[]) {
// 创建使用者
User user= new User();
// 生成原型实例
Product01 product01 = new Product01('*');
Product01 product011 = new Product01('#');
Product02 product02 = new Product02('^');
// 注册原型实例
user.register("p01", product01);
user.register("p011", product011);
user.register("p02", product02);
// 根据原型实例生成实例
Product p1 = user.create("p01");
p1.use("hello world");
Product p2 = user.create("p011");
p2.use("hello java");
Product p3 = user.create("p02");
p3.use("hello prototype");
}
}
运行截图,如下所示:
参考文献:
- 图解设计模式 - 结成浩著、杨文轩译 - 人民邮电出版社