拔一根猴毛,变出十万个孙悟空
故事背景
在java中,我们一般创建实例的时候可以使用了new
关键词指定类名来生成类的实例。例如:
Preson p = new Person();
或者
Person p = Person.getInstance();
但是是在实际开发过程中,有时候会有“不指定类名的前提下生成实例”的需求。这种情况下,就不能通过上面的这种方式生成实例!
除了上面这种情况外,还有就是 对象的种类繁多,如果每一个都作为一个类,那么要编写很多类文件!
可以通过一个原型对象克隆出多个一模一样的对象!
原型模式和单例模式区别:
单例模式:在系统只存在或者说只创建唯一的一个对象。
原型模式:在系统中存在或者说创建多个对象。
故事主角
原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。
原型模式的核心在于如何实现克隆方法,下种在Java语言中常用的克隆实现方法:
- Java语言提供的clone()方法(浅拷贝)
- Java语言提供的序列化方法(深拷贝)
武功修炼
使用原型管理器 演示简单的原型模式:
// 抽象原型类
public interface Product extends Cloneable{
/**
* 产品使用方法
* @param str
*/
abstract void use(String str);
/**
* 复制实例对象的方法
* @return
*/
abstract Product createClone();
}
public class MessageProduct implements Product{
private String flagStr;
public MessageProduct(){}
public MessageProduct(String str){
this.flagStr = str;
}
@Override
public void use(String str) {
for (int i = 0; i < str.length(); i++) {
System.out.print(flagStr);
}
System.out.println("");
System.out.println("-----"+ str+"---------");
for (int i = 0; i < str.length(); i++) {
System.out.print(flagStr);
}
}
@Override
public Product createClone() {
Product product = null;
try {
product = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
}
}
public class UnderLineProduct implements Product {
private String flagStr;
public UnderLineProduct(){}
public UnderLineProduct(String str){
this.flagStr = str;
}
@Override
public void use(String str) {
for (int i = 0; i < str.length(); i++) {
System.out.print(flagStr);
}
System.out.println("");
System.out.println(str);
for (int i = 0; i < str.length(); i++) {
System.out.print(flagStr);
}
System.out.println("");
}
@Override
public Product createClone() {
Product product = null;
try {
product = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
}
}
// Product 的管理器
public class ManageProduct {
private HashMap map = new HashMap();
/**
* 通过名称注册Product
* @param name
* @param product
*/
public void register(String name,Product product){
map.put(name, product);
}
/**
* 创建Product
* @param protoName
* @return
*/
public Product createProduct(String protoName){
Product product = (Product)map.get(protoName);
return product.createClone();
}
public class TestMain {
public static void main(String[] args) {
ManageProduct manageProduct = new ManageProduct();
// 准备
manageProduct.register("mesOne",new UnderLineProduct("|"));
manageProduct.register("mesTwo",new UnderLineProduct("——"));
manageProduct.register("mesThree",new MessageProduct("(*)"));
//生成
Product p1 = manageProduct.createProduct("mesOne");
p1.use("你好,China!");
Product p2 = manageProduct.createProduct("mesTwo");
p2.use("你好,China!");
Product p3 = manageProduct.createProduct("mesThree");
p3.use("你好,China!");
}
}
|||||||||
你好,China!
|||||||||
——————————————————
你好,China!
——————————————————
(*)(*)(*)(*)(*)(*)(*)(*)(*)
-----你好,China!---------
(*)(*)(*)(*)(*)(*)(*)(*)(*)
总结
优点:
- 原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。
- 在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。
缺点:
需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。
在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。
参考
- 史上最全设计模式导学
- 《Head First 设计模式》
- 《图解设计模式》
如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!
如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!
欢迎访问我的csdn博客,我们一同成长!
不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!