Gof23-Portotype模式
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
介绍
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。也就是根据现有的实例来生成新的实例。
主要解决:在运行期根据原型创建实例或删除原型。
何时使用:
1、对象种类繁多,无法将它们整合到一个类中时
需要处理的类太多,如果将它们分别作为一个类,那么就需要编写很多类文件。
2、难以根据类生成实例时
生成实例的过程太为复杂,难以根据类生成新的实例。
3、想解耦框架与生成的实例时
生成实例的框架不依赖具体的类,可以先注册一个原型到map中,然后通过复制该原型生成新的实例。
关键代码:
1、实现克隆操作,在 JAVA 实现 Cloneable 接口,重写 clone()
2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。
使用场景:
1、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2、性能和安全要求的场景。
3、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
4、一个对象多个修改者的场景。
5、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
6、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
注意事项:
与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
角色:
- Prototype(抽象原型)
- 负责定义类中应该有哪些方法,以及定义复制现有实例生成新实例的方法。
- ConcreatePrototype(具体的原型)
- 负责实现上面接口定义的方法。
- Client(使用者)
- 负责使用复制实例的方法生吃新的实例。
UML类图:
实例
Product接口,(抽象原型角色)
/**
* 复制功能的接口,继承了Cloneable接口,实现了该接口的类的实例,可以调用clone方法实现自动复制实例
*/
public interface Product extends Cloneable{
/**
* 使用的方法,具体怎么使用,不用关心,子类自己实现
* @param s
*/
public abstract void use(String s);
/**
* 用于复制实例的方法
* @return
*/
public abstract Product createProduct();
}
Manager类,(使用者角色)
public class Manager {
/**
* 用于保存实例和名字之间的对应关系
*/
private Map<String, Product> showCase = new HashMap<>();
/**
* 接收到一组名字和Product接口的子类,注册到showCase中
* @param name 类名
* @param proto Product的子类,它实现了Product,也就可以调用它的use方法和createClone方法
*/
public void register(String name, Product proto) {
showCase.put(name, proto);
}
/**
* 通过该方法复制实例,Manager类和Product接口没有出现它们的子类,就可以独立修改这两个类,而不受它们子类的影响
* 降低了代码的耦合性
* @param protoName 模板名字
* @return
*/
public Product create(String protoName) {
Product product = showCase.get(protoName);
return product.createProduct();
}
}
MeeageBox:(具体的原型角色)
public class MessageBox implements Product{
/**
* 用于装饰的字符
*/
private char decoChar;
public MessageBox(char decoChar) {
this.decoChar = decoChar;
}
/**
* 自定义use方法
* @param s
* @throws UnsupportedEncodingException
*/
@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();
}
/**
* 实现复制的方法,通过调用父类的clone方法实现复制
* @return
*/
@Override
public Product createProduct() {
Product product = null;
try {
product = (Product)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
}
}
Main类,测试类
public class Main {
public static void main(String[] args) {
Manager manager = new Manager();
MessageBox messageBox = new MessageBox('*');
// 将具体的原型类注册到manager中
manager.register("warning", messageBox);
// 通过manager获得MessageBox的实例
Product product = manager.create("warning");
product.use("Hello, world");
}
}
/**
* ****************
* * Hello, world *
* ****************
*/
笔者学习设计模式的记录与心得。

查看23道真题和解析