• 设计模式


    原型模式是创建型模式的一种,其特点在于通过 “复制” 一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的 “原型”,这个原型是可定制的。

    类图

    代码实现

    用于测试的 JavaBean:

    package com.huey.pattern.prototype;
    
    import java.io.Serializable;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class TestBean implements Serializable {
        
        /**
         * 
         */
        private static final long serialVersionUID = -2351683706932774662L;
        
        @Getter @Setter
        private String testValue;
    
    }

    抽象原型:

    package com.huey.pattern.prototype;
    
    /**
     * the abstract prototype
     * @author  huey
     * @version 1.0 
     * @created 2015-11-27
     */
    public abstract class Prototype implements Cloneable {
        
        public Prototype() {
            System.out.println("Prototype is constructed.");
        }
        
        @Override
        protected Prototype clone() {
            try {
                return (Prototype) super.clone();
            } catch (Exception e) {
                return null;
            }
        }
    
    }

    具体原型:

    package com.huey.pattern.prototype;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    
    /**
     * the concrete prototype
     * @author  huey
     * @version 1.0 
     * @created 2015-11-27
     */
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class ShallowCopyBean extends Prototype {
    
        @Getter @Setter
        private Integer primitiveValue;
        @Getter @Setter
        private TestBean customValue;
        
    }

    单元测试:

    package com.huey.pattern.prototype;
    
    public class ShallowCopyBeanTest {
    
        public static void main(String[] args) {        
            Prototype cloneableBean = new ShallowCopyBean(10, new TestBean("AAA"));
            System.out.println("cloneableBean: " + cloneableBean);
            
            ShallowCopyBean clonedBean = (ShallowCopyBean) cloneableBean.clone();
            clonedBean.setPrimitiveValue(100);
            clonedBean.getCustomValue().setTestValue("BBB");
            System.out.println("cloneableBean: " + cloneableBean);
            System.out.println("clonedBean: " + clonedBean);
        }
        
    }

    结果输出:

    Prototype is constructed.
    cloneableBean: ShallowCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
    cloneableBean: ShallowCopyBean(primitiveValue=10, customValue=TestBean(testValue=BBB))
    clonedBean: ShallowCopyBean(primitiveValue=100, customValue=TestBean(testValue=BBB))

    从输出可以看到,原型只被构造一次。但是这里需要注意当 clonedBean 的引用对象 customVaule 的内容发生改变时,cloneableBean 的 customVaule 也跟着改变。这就是深拷贝与浅拷贝的问题,Java 中,Object 类的 clone 方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

    深拷贝

    实现深拷贝可以在重写 clone 方法中,对数组、容器对象、引用对象等自己进行拷贝。

    还可以使用一个技巧,就是利用序列化的机制来实现,通过将对象序列化到输出流中,然后将其读回,这样产生的新对象是对现有对象的一个深拷贝。

    代码实现

    可序列化的抽象原型:

    package com.huey.pattern.prototype;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    /**
     * the abstract prototype
     * @author  huey
     * @version 1.0 
     * @created 2015-11-27
     */
    public abstract class SerialCloneable implements Serializable, Cloneable {
    
        /**
         * 
         */
        private static final long serialVersionUID = -2477239830471073680L;
    
        @Override
        protected Object clone() {
            try {
                /**
                 * serialize the object to the output stream
                 */
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                ObjectOutputStream output = new ObjectOutputStream(bout);
                output.writeObject(this);
                output.close();
                
                /**
                 * deserialize the object from the input stream
                 */
                ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
                ObjectInputStream input = new ObjectInputStream(bin);
                Object result = input.readObject(); 
                input.close();
                
                return result;
            } catch (Exception e) {
                return null;
            }
        }
    }

    具体原型:

    package com.huey.pattern.prototype;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    
    /**
     * the concrete prototype
     * @author  huey
     * @version 1.0 
     * @created 2015-11-27
     */
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class DeepCopyBean extends SerialCloneable {
    
        /**
         * 
         */
        private static final long serialVersionUID = -959424582381713341L;
        
        @Getter @Setter
        private Integer primitiveValue;
        @Getter @Setter
        private TestBean customValue;
        
    }

    单元测试:

    package com.huey.pattern.prototype;
    
    public class DeepCopyBeanTest {
        
        public static void main(String[] args) {
            
            SerialCloneable cloneableBean = new DeepCopyBean(10, new TestBean("AAA"));
            System.out.println("cloneableBean: " + cloneableBean);
            
            DeepCopyBean clonedBean = (DeepCopyBean) cloneableBean.clone();
            clonedBean.setPrimitiveValue(100);
            clonedBean.getCustomValue().setTestValue("BBB");
            System.out.println("cloneableBean: " + cloneableBean);
            System.out.println("clonedBean: " + clonedBean);
        }
    
    }

    结果输出:

    cloneableBean: DeepCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
    cloneableBean: DeepCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
    clonedBean: DeepCopyBean(primitiveValue=100, customValue=TestBean(testValue=BBB))

    从输出可以看到,clonedBean 的引用对象 customVaule 的内容发生改变时,不会影响到 cloneableBean 的 customVaule。

    原型模式的适用场合

    1) 产生对象过程比较复杂,初始化需要许多资源时;

    2) 希望框架原型和产生对象分开时;

    3) 同一个对象可能会供其他调用者使用访问时。

  • 相关阅读:
    Shell – Wget 克隆网站
    Tools
    Tools
    Tools
    Ubuntu
    android studio中配置X5 webview时的一个坑
    android studio中Fragment使用webview返回上一页的问题
    android studio中退出时弹出对话框
    android studio中使用x5 webview来读写cookies的问题
    flask blueprint出现的坑
  • 原文地址:https://www.cnblogs.com/huey/p/5001374.html
Copyright © 2020-2023  润新知