设计模式之原型模式

原型模式

文章目录

定义

原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单,使用的场景才非常地多,其定义如下:

Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。)

优缺点

优点:

  1. 性能优良

    原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

  2. 逃避构造函数的约束

    这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。

实现方式

浅拷贝
java 复制代码
public class Thing implements Cloneable{
     //定义一个私有变量
     private ArrayList<String> arrayList = new ArrayList<String>();
     @Override
     public Thing clone(){
             Thing thing=null;
             try {
                    thing = (Thing)super.clone();
             } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
             }
             return thing;
     }
     //设置HashMap的值
     public void setValue(String value){
             this.arrayList.add(value);
     }
     //取得arrayList的值
     public ArrayList<String> getValue(){
             return this.arrayList;
     }
}

在Thing类中增加一个私有变量arrayLis,类型为ArrayList,然后通过setValue和getValue分别进行设置和取值,我们来看场景类是如何拷贝的

java 复制代码
public class Client {
     public static void main(String[] args) {
             //产生一个对象
             Thing thing = new Thing();
             //设置一个值
             thing.setValue("张三");              
             //拷贝一个对象
             Thing cloneThing = thing.clone();
             cloneThing.setValue("李四");         
             System.out.println(thing.getValue());
     }
}

猜想一下运行结果应该是什么?是仅一个"张三"吗?运行结果如下所示:

复制代码
[张三,李四]

怎么会这样呢?怎么会有李四呢?是因为Java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一种非常不安全的方式,在实际项目中使用还是比较少的(当然,这是也是一种"危机"环境的一种救命方式)。你可能会比较奇怪,为什么在Mail那个类中就可以使用String类型,而不会产生由浅拷贝带来的问题呢?内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,读者在使用的时候就把String当做基本类使用即可

注意 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。

深拷贝
java 复制代码
public class Thing implements Cloneable{
     //定义一个私有变量
     private ArrayList<String> arrayList = new ArrayList<String>();
     @Override
     public Thing clone(){
             Thing thing=null;
             try {
                   thing = (Thing)super.clone();
                       thing.arrayList = (ArrayList<String>)this.arrayList.clone();


             } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
             }
             return thing;
     }
}

运行结果如下所示:


复制代码
[张三]

该方法就实现了完全的拷贝,两个对象之间没有任何的瓜葛了,你修改你的,我修改我的,不相互影响,这种拷贝就叫做深拷贝。深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下。

注意 深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。

日常开发中的应用

我们日常开发可以使用apachecommons-lang3中的SerializationUtils.clone方法进行对象的深拷贝。

相关推荐
white-persist3 分钟前
Python实例方法与Python类的构造方法全解析
开发语言·前端·python·原型模式
李广坤7 小时前
状态模式(State Pattern)
设计模式
李广坤8 小时前
观察者模式(Observer Pattern)
设计模式
李广坤9 小时前
中介者模式(Mediator Pattern)
设计模式
李广坤9 小时前
迭代器模式(Iterator Pattern)
设计模式
李广坤10 小时前
解释器模式(Interpreter Pattern)
设计模式
阿无,12 小时前
java23种设计模式之前言
设计模式
Asort13 小时前
JavaScript设计模式(八):组合模式(Composite)——构建灵活可扩展的树形对象结构
前端·javascript·设计模式
数据智能老司机13 小时前
数据工程设计模式——数据基础
大数据·设计模式·架构
笨手笨脚の16 小时前
设计模式-代理模式
设计模式·代理模式·aop·动态代理·结构型设计模式