zoukankan      html  css  js  c++  java
  • 学习设计模式之原型模式

    原型模式
    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    结构图
    在这里插入图片描述

    1. Prototype:原型类,声明一个克隆自身的接口
    2. ConcretePrototype:具体原型类,实现一个克隆自身的操作
    3. Client:客户端,让一个原型克隆自身从而创建一个新的对象

    代码实现

    public class PrototypeA01 implements Cloneable {
    
        private int id;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        @Override
        public String toString() {
            return "PrototypeA01{" +
                    "id=" + id +
                    '}';
        }
    }
    
    public class TestMain {
        public static void main(String[] args) throws CloneNotSupportedException {
            PrototypeA p = new PrototypeA();
            p.setId(1);
            System.out.println(p);
            PrototypeA clonep = (PrototypeA) p.clone();
            System.out.println(clonep);
        }
    }
    

    运行结果
    PrototypeA{id=‘1’}
    PrototypeA{id=‘1’}

    Process finished with exit code 0

    关键点在于,实现 Cloneable 接口以及用 object 的 clone 方法。这样就可以不用实例化对象,直接克隆就可以了,只需要实现这个接口就可以完成原型模式了!

    浅克隆与深克隆
    在原型模式中有两个概念我们需要了解一下,就是浅克隆和深克隆的概念。如果对象里的属性都是值类型那么没有问题,如果对象里有引用类型则是复制引用而不是复制引用的对象,因此原始对象及其复制对象引用同一个对象。

    浅克隆
    在这里插入图片描述
    深克隆
    在这里插入图片描述

    例如

    public class PrototypeA01 implements Cloneable {
    
        private int id;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        @Override
        public String toString() {
            return "PrototypeA01{" +
                    "id=" + id +
                    '}';
        }
    }
    
    public class PrototypeA01 {
    
        private int id;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
        
        @Override
        public String toString() {
            return "PrototypeA01{" +
                    "id=" + id +
                    '}';
        }
    }
    
    public class TestMain {
        public static void main(String[] args) throws CloneNotSupportedException {
            PrototypeA p = new PrototypeA();
            PrototypeA01 pa01 = new PrototypeA01();
            pa01.setId(2);
            p.setId(1);
            p.setPrototypeA01(pa01);
            System.out.println(p);
            PrototypeA clonep = (PrototypeA) p.clone();
            System.out.println(clonep);
            // 现在来修改这个对象
            pa01.setId(3);
            System.out.println(p);
            System.out.println(clonep);
        }
    }
    

    运行结果
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}

    Process finished with exit code 0

    从运行结果来看原始对象和克隆对象的属性都改变了。深克隆,我就不用多说了吧,就是什么都是单独的!全部复制,然后各自独立。你修改克隆对象对于原型对象没有丝毫影响。

    代码实现之需要在对应的属性类上再次实现 Cloneable 接口以及用 object 的 clone 方法就可以了。

    public class PrototypeA implements Cloneable {
    
        private int id;
    
        private PrototypeA01 prototypeA01;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public PrototypeA01 getPrototypeA01() {
            return prototypeA01;
        }
    
        public void setPrototypeA01(PrototypeA01 prototypeA01) {
            this.prototypeA01 = prototypeA01;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            PrototypeA clone = (PrototypeA) super.clone();
            clone.setPrototypeA01((PrototypeA01) getPrototypeA01().clone());
            return clone;
        }
    
        @Override
        public String toString() {
            return "PrototypeA{" +
                    "id=" + id +
                    ", prototypeA01=" + prototypeA01 +
                    '}';
        }
    }
    
    public class PrototypeA01 implements Cloneable {
    
        private int id;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        @Override
        public String toString() {
            return "PrototypeA01{" +
                    "id=" + id +
                    '}';
        }
    }
    
    public class TestMain {
        public static void main(String[] args) throws CloneNotSupportedException {
            PrototypeA p = new PrototypeA();
            PrototypeA01 pa01 = new PrototypeA01();
            pa01.setId(2);
            p.setId(1);
            p.setPrototypeA01(pa01);
            System.out.println(p);
            PrototypeA clonep = (PrototypeA) p.clone();
            System.out.println(clonep);
            // 现在来修改这个对象
            pa01.setId(3);
            System.out.println(p);
            System.out.println(clonep);
        }
    }
    

    运行结果
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}
    PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}

    Process finished with exit code 0

    从结果来看都是单独的!全部复制,然后各自独立。

    总结
    原型模式的Prototype类必须继承Cloneable接口,并对接口中的clone方法进行实现。

    优点
    使用原型模型创建一个对象比直接new一个对象更有效率,因为它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

    缺点
    在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

    勿在浮沙筑高台 ——个人浅见,难免有误导之处,麻烦请指出。
  • 相关阅读:
    【hihocoder】1237 : Farthest Point 微软2016校招在线笔试题
    POJ 1061青蛙的约会。求解(x+mT)%L=(y+nT)%L的最小步数T。
    Gym 100633G Nano alarm-clocks
    shell script 的追踪与 debug
    vim使用心得
    Linux修改vimrc配置文件,让vi更贴心
    shell script中的case……esac判断
    stl容器区别: vector list deque set map-底层实现
    const对象为什么可以在头文件中定义
    shell script中的syntax error near unexpected token `then' 问题
  • 原文地址:https://www.cnblogs.com/liufeichn/p/11961650.html
Copyright © 2011-2022 走看看