Prototype模式
在JAVA中通常通过new关键字生成实例。像这样使用new来生成实例时,必须指定类名。但有时需要根据现有情况下来生成新的实例。
-
对象种类繁多,无法将他们整合到一个类中
需要处理的对象太多,如果分别作为一个类,必须编写很多个类文件。
-
难以根据类生成实例
生成实例的过程太复杂,很难根据类来生成实例。
-
解耦框架与生成的实例
生成实例的框架不依赖具体的类。
事例程序
类和接口一览表
名字 | 说明 |
---|---|
Product | 声明抽象方法use和createClone的接口 |
Manager | 调用createClone方法复制实例的类 |
MessageBox | 实现use和createClone |
UnderlinePen | 实现use和createClone |
Main | 测试程序 |
虽然Manager类会调用createClone方法,但对拘役要复制哪一个类一无所知。不过们只要实现了product接口的类,调用它的createClone方法就可复制出新的实例。
MessageBox和UnderlinePen类是两个实现了Product接口的类。只要事先将两个类注册到manager中就可以随时复制新的实例。
类图
代码清单
Product接口
product接口是复制功能的接口,继承了java.lang.Cloneable。 use方法是使用的方法,具体使用交给子类。 createClone方法用于复制实例的方法。
public interface Product extends Cloneable{
public abstract void use(String s);
public abstract Product createClone();
}
复制代码
Manager类
Manager类使用product接口来复制实例。 showCase保存“名字”和“实例”之间的对应关系。 register会将收到的名字和product接口注册到showcase中。这里的product具体什么类型是不知道的,但有一点可以确认,它肯定是实现了product接口的类的实例。 在product和manager中没有出现messageBox和underlinePen,这就意味着魔门可以独立修改product和manager。一旦使用了别的类,就意味着该类与其他类精密的耦合在一起了。 product是连接manager与其他具体类的桥梁。
public class Manager {
private HashMap<String, Product> showCase = new HashMap<>();
public void register(String name, Product proto) {
showCase.put(name, proto);
}
public Product create(String protoName) {
Product product = showCase.get(protoName);
return product.createClone();
}
}
复制代码
MessageBox类
use使用效果如下:
***************
* Hello,world *
***************
复制代码
createClone方法用于复制自己。它内部调用的clone方法是JAVA定义的方法,用于复制自己。该类实现了Clonable接口我们才能调用这个方法,否则会抛出CloneNotSupportedException异常。因为MessageBox实现了Product,而Product继承了Clonable,所以不会抛异常。需要注意的是: Clonable本身并没有定义深任何方法,只是告诉程序可以调用clone方法。
当其它类要求复制实例时,必须调用createClone这样的方法,然后在内部调用clone方法。
@Data
public class MessageBox implements 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("");
}
@Override
public Product createClone() {
Product p =null;
try {
p =(Product) this.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
复制代码
UnderlinePen类
use方法:
"Hello,world"
~~~~~~~~~~~
复制代码
@Data
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) this.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
复制代码
Main类
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");
}
}
复制代码
结果:
"Hello,world"
~~~~~~~~~~~
***************
* Hello,world *
***************
///
/ Hello,world /
///
复制代码
登场角色
-
原型
负责定义用于复制现有实例来生成新势力的方法。----product
-
具体原型
负责实现复制现有实例并生成新实例的方法。----MessageBox和UnderlinePen
-
使用者
负责使用复制方法生成新实例。----Manager
扩展
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。