原型模式

作者: 程序员丶星霖 | 来源:发表于2017-04-24 18:36 被阅读49次

    原型模式

    定义

    原型模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。
    英文定义:Specify the kinds of objects to create using a prototypical instance , and create new objects by copying this prototype .(用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。)

    原型模式的UML类图如下所示

    原型模式.jpg

    上图中主要涉及一下角色:

    • 客户端(Client):客户端提出创建对象的请求。
    • 抽象原型(Prototype):通常由一个Java接口或者Java抽象类来实现,从而为具体原型设立好规范。
    • 具体原型(ConcretePrototype):被复制的具体对象,这个具体角色实现了抽象原型角色所要求实现的方法。

    原型模式的通用代码如下:

    //原型模式通用源码
    public class PrototypeClass implements Cloneable{
        //覆写父类Object方法
        @Override
        public PrototypeClass clone(){
            PrototypeClass prototypeClass = null;
            try{
                prototypeClass = (PrototypeClass)super.clone();
            }catch(CloneNotSupportedExecption e){
                //异常处理
            }
            return prototypeClass;
        }
    }
    

    优缺点

    优点:

    • 性能优良:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多。
    • 逃避构造函数的约束:直接在内存中拷贝,构造函数是不会执行的。
    • 提供简化的创建结构。
    • 具有给一个应用软件动态加载新功能的能力。

    缺点:

    • 每一个类都必须配备一个复制方法,对于全新的类来说不是很难,而对已有的类来说实现clone()方法不一定很容易,而且在进行比较深层次的复制时也需要编写一定量的代码。

    应用场景:

    • 资源优化:类初始化需要消化非常多的资源。
    • 性能和安全要求:通过new产生一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
    • 一个对象多个修改者:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
    • 隐藏复制操作的细节

    注意事项

    1.构造函数不会被执行

    一个实现了Cloneable并重写了clone方法的类,在对象拷贝时构造函数是不会被执行的。

    代码如下所示:

    public class Thing implements Cloneable{
        public Thing(){
            System.out.println("构造函数被执行了......");
        }
        @Override
        public Thing clone(){
            Thing thing = null;
            try{
                thing = (Thing)super.clone();
            }catch(CloneNotSupportedExecption e){
                e.printStackTrace();
            }
            return thing;
        }
    }
    
    public class Client{
        public static void main(String[] args){
            //产生一个对象
            Thing thing = new Thing();
            //拷贝一个对象
            Thing cloneThing = thing.clone();
        }
    }
    
    2.浅拷贝和深拷贝

    浅拷贝:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址。浅拷贝是对基本数据类型和String类型而言的。

    //浅拷贝
    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(CloneNotSupportedExecption e){
                e.printStackTrace();
            }
            return thing;
        }
        //设置HashMap的值
        public void setValue(String value){
            this.arrayList.add(value);
        }
        //取得ArrayList的值
        public ArrayList<String> getValue(){
            return this.arrayList;
        }
    }
    
    //浅拷贝测试
    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());
        }
    }
    

    深拷贝:实现完全的拷贝,两个对象之间没有任何的瓜葛。深拷贝是对其他引用类型而言的。

    代码如下所示:

    //深拷贝
    public class Thing implements Cloneable{
        //定义一个私有变量
        private ArrayList<String> arrayList = new ArrayList<String>();
        @Override
        public Thing clone(){
            Thing thing = null;
            try{
                thing = (Thing)super.clone();
                this.arrayList = (ArrayList<String>)this.arrayList.clone();
            }catch(CloneNotSupportedExecption e){
                e.printStackTrace();
            }
            return thing;
        }
        
    }
    

    注意:
    使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:

    • 类是成员变量,而不是方法内变量;
    • 必须是一个可变的引用对象,而不是一个原始类型或不可变对象。
    3.clone与final
    • 要使用clone方法,类的成员变量上不要增加final关键字。
    欢迎大家关注我的微信公众号
    二维码.jpg

    相关文章

      网友评论

        本文标题:原型模式

        本文链接:https://www.haomeiwen.com/subject/vpbjzttx.html