八、创建型模式——原型模式
2018-04-03 18:37
281 查看
西游记中的孙悟空神通广大,拔一根毫毛喊一声:变。一个新的孙悟空就出来了,编程的时候经常也需要用到这个技能。不过程序中的孙悟空比西游记中的孙悟空更厉害,它还能再拔毛变悟空。1.定义 通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。所谓原型模式,就是java中的克隆技术,以某个对象为原型。复制出新的对象。显然新的对象具备原型对象的特点。效率高(避免了重新执行构造过程步骤)克隆类似于new,但和new不同。new创建新的对象属性采用的是默认值。克隆出来的对象的属性值完全和原型对象相同。并且克隆出的新对象不会影响原型对象,克隆后。还可以再修改克隆对象的值。要实现原型模式,必须实现Cloneable接口,而这个接口里面是空的。
2.原理讲解参考J2EE模块的对象克隆部分
3.原型模式有两种表现形式:(1)简单形式
![](https://img-blog.csdn.net/20180403182832631?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDAzNjQ2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
具体原型角色
public class ConcretePrototype1 implements Prototype {
public Prototype clone(){
//最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了
Prototype prototype = super.clone();
return prototype;
}
}客户角色public class Client {
private Prototype prototype;
public Client(Prototype prototype){
this.prototype = prototype;
}
public void operation(Prototype example){
//需要创建原型接口的对象
Prototype copyPrototype = prototype.clone();
}
}(2)登记形式
![](https://img-blog.csdn.net/20180403182936214?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDAzNjQ2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
作为原型模式的第二种形式,它多了一个原型管理器(PrototypeManager)角色,该角色的作用是:创建具体原型类的对象,并记录每一个被创建的对象。
public class PrototypeManager {
/**
* 用来记录原型的编号和原型实例的对应关系
*/
private static Map<String,Prototype> map = new HashMap<String,Prototype>();
/**
* 私有化构造方法,避免外部创建实例
*/
private PrototypeManager(){}
//向原型管理器里面添加或是修改某个原型注册
public synchronized static void setPrototype(String prototypeId , Prototype prototype){
map.put(prototypeId, prototype);
}
//从原型管理器里面删除某个原型
public synchronized static void removePrototype(String prototypeId){
map.remove(prototypeId);
}
//给出聚簇大小,也就是集合中有多少个克隆的对象的方法
public int getSize() {
return map.size;
}
}4.深复制和浅复制在Java中,复制对象是通过clone()实现的,先创建一个原型类:
5.原型模式的使用分析 当创建给定类的实例的过程很麻烦,很复杂,或者很消耗的代价太高的时候,我们需要使用原型模式。 因为原型模式创建一个新对象,就想复制粘贴一样简单。原型模式的优点(1)根据客户端要求实现动态创建对象,由于创建产品类实例的方法是产品类内部具有的,因此增加产品对整个结构没有影响(2)使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。(3) 原型模式类似于工厂模式,但它没有了工厂模式中的抽象工厂和具体工厂的层级关系,代码结构更清晰和简单。原型模式的注意事项(1)使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不 会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为 private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的。(2)在使用时要注意深拷贝与浅拷贝的问题。clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
2.原理讲解参考J2EE模块的对象克隆部分
3.原型模式有两种表现形式:(1)简单形式
客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
具体原型角色
public class ConcretePrototype1 implements Prototype {
public Prototype clone(){
//最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了
Prototype prototype = super.clone();
return prototype;
}
}客户角色public class Client {
private Prototype prototype;
public Client(Prototype prototype){
this.prototype = prototype;
}
public void operation(Prototype example){
//需要创建原型接口的对象
Prototype copyPrototype = prototype.clone();
}
}(2)登记形式
作为原型模式的第二种形式,它多了一个原型管理器(PrototypeManager)角色,该角色的作用是:创建具体原型类的对象,并记录每一个被创建的对象。
public class PrototypeManager {
/**
* 用来记录原型的编号和原型实例的对应关系
*/
private static Map<String,Prototype> map = new HashMap<String,Prototype>();
/**
* 私有化构造方法,避免外部创建实例
*/
private PrototypeManager(){}
//向原型管理器里面添加或是修改某个原型注册
public synchronized static void setPrototype(String prototypeId , Prototype prototype){
map.put(prototypeId, prototype);
}
//从原型管理器里面删除某个原型
public synchronized static void removePrototype(String prototypeId){
map.remove(prototypeId);
}
//给出聚簇大小,也就是集合中有多少个克隆的对象的方法
public int getSize() {
return map.size;
}
}4.深复制和浅复制在Java中,复制对象是通过clone()实现的,先创建一个原型类:
public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } }很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法。(1)浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。(2)深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。 深复制有两种方式一种通过不断克隆引用属性完成复制一种是通过流的方式此处,写一个深浅复制的例子:
public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /* 浅复制 */ public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } /* 深复制 */ public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this.string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this.obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; }把对象写到流里的过程是串行化的过程,但是在Java程序师圈子里又非常形象地成为冷冻过程,而把对象从流中读出来的并行化过程成为解冻。写到流里的是对象的一个拷贝,而原始对象仍然存在于JVM里面。所以具有解冻的功能。
5.原型模式的使用分析 当创建给定类的实例的过程很麻烦,很复杂,或者很消耗的代价太高的时候,我们需要使用原型模式。 因为原型模式创建一个新对象,就想复制粘贴一样简单。原型模式的优点(1)根据客户端要求实现动态创建对象,由于创建产品类实例的方法是产品类内部具有的,因此增加产品对整个结构没有影响(2)使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。(3) 原型模式类似于工厂模式,但它没有了工厂模式中的抽象工厂和具体工厂的层级关系,代码结构更清晰和简单。原型模式的注意事项(1)使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不 会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为 private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的。(2)在使用时要注意深拷贝与浅拷贝的问题。clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
相关文章推荐
- 【设计模式学习笔记五】【创建型模式】【原型模式(Prototype)】
- JAVA设计模式创建型模式之原型模式
- 设计模式-创建型-原型模式
- 从FLC中学习的设计模式系列-创建型模式(5)-原型
- C#设计模式之五原型模式(Prototype Pattern)【创建型】
- 1.4 Prototype(原型) -- 对象创建型模式
- (六)(创建型模式)原型模式
- 创建型模式-原型模式
- Prototype原型(创建型模式)
- 设计模式(2)-创建型-原型模式(Prototype)
- 创建型之原型模式
- 创建型模式之五——原型模式
- 设计模式(四)原型模式(创建型)
- JAVA设计模式(5) —<创建型>原型模式(Prototype)
- 创建型模式--原型模式
- (第Ⅱ部分 创建型模式篇)第5章 原型模式(Protype Pattern)
- 23种设计模式2--创建型模式(工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式)
- 【设计模式】创建型模式-原型模式
- 设计模式(5)-创建型-原型(Prototype)模式(个人笔记)
- Java技术_每天掌握一种设计模式(006)_使用场景及简单实例(创建型:原型模式)