zoukankan      html  css  js  c++  java
  • 原型模式

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

    原型模式主要适用于以下场景:

    1. 类初始化消耗资源较多。
    2. new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
    3. 构造函数比较复杂。
    4. 循环体中生产大量对象时。

    数据内容完全一样,但实例不同

    1. 能够直接拷贝其实际内容的数据类型/只支持9种,八大基本数据类型+String
    2. 深拷贝,其它类型也能拷贝

    简单克隆

    /**
     * 原型接口
     */
    public interface ProtoType {
        ProtoType clone();
    }
    
    
    /**
     * 具体需要克隆的对象
     */
    public class ConcretePrototype implements ProtoType{
        private int age;
        private String name;
        private List hobbies;
    
        @Override
        public ProtoType clone() {
            ConcretePrototype concretePrototype = new ConcretePrototype();
            concretePrototype.setAge(this.age);
            concretePrototype.setHobbies(this.hobbies);
            concretePrototype.setName(this.name);
            return concretePrototype;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List hobbies) {
            this.hobbies = hobbies;
        }
    }
    
    
    
    public class Client {
        private ProtoType protoType;
        public Client(ProtoType protoType){
            this.protoType= protoType;
        }
        public ProtoType startClone(){
            return protoType.clone();
        }
    }
    
    测试
    
    public class Test {
        public static void main(String[] args){
            ConcretePrototype concretePrototype = new ConcretePrototype();
            concretePrototype.setAge(11);
            concretePrototype.setName("pro");
            ArrayList<Object> arrayList = new ArrayList<>();
            arrayList.add(1);
            concretePrototype.setHobbies(arrayList);
            System.out.println(concretePrototype);
    
            Client client = new Client(concretePrototype);
            ConcretePrototype protoType = (ConcretePrototype) client.startClone();
            System.out.println(protoType);
            System.out.println("克隆对象中的引用类型地址值:" + concretePrototype.getHobbies());
            System.out.println("原对象中的引用类型地址值:" + protoType.getHobbies());
            System.out.println("克隆对象中的hobbies:" + Arrays.asList(concretePrototype.getHobbies()));
            System.out.println("原对象中的hobbies:" + Arrays.asList(protoType.getHobbies()));
            System.out.println("对象地址比较:"+(protoType.getHobbies() == concretePrototype.getHobbies()));
    
            ArrayList<Object> hobbies = (ArrayList<Object>) concretePrototype.getHobbies();
            hobbies.add(2);
            concretePrototype.setHobbies(hobbies);
            System.out.println("克隆对象中的hobbies:" + Arrays.asList(concretePrototype.getHobbies()));
            System.out.println("原对象中的hobbies:" + Arrays.asList(protoType.getHobbies()));
    //        com.vip.prototype.simple.ConcretePrototype@4b67cf4d
    //        com.vip.prototype.simple.ConcretePrototype@7ea987ac
    //        克隆对象中的引用类型地址值:[1]
    //        原对象中的引用类型地址值:[1]
    //        克隆对象中的hobbies:[[1]]
    //        原对象中的hobbies:[[1]]
    //        对象地址比较:true
    //        克隆对象中的hobbies:[[1, 2]]
    //        原对象中的hobbies:[[1, 2]]
    
    //        从测试结果看出 hobbies 的引用地址是相同的,意味着复制的不是值,而是引用的地址。
    //        修改任意一个对象中的属性值,concretePrototype 和 protoType 的 hobbies 值都会改变。这就是我们常说的浅克隆。
    //        只是完整 复制了值类型数据,没有赋值引用对象。
        }
    }
    
    

    简单实例:

    
    package prototype.simple;
    
    import java.util.ArrayList;
    import java.util.Date;
    
    /**
     * 克隆基于字节码
     * 底层是c语言写的
     * 不走构造方法
     */
    public class ConcretePrototype implements Cloneable{
        private int age;
        private String name;
        public ArrayList<String> list = new ArrayList<>();
        private Date date;
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            ConcretePrototype prototype = null;
    
            //能够直接拷贝其实际内容的数据类型/只支持9种,八大基本数据类型+String
            prototype = (ConcretePrototype) super.clone();
            //手动克隆
            prototype.list = (ArrayList<String>) list.clone();
    
            return prototype;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    package prototype.simple;
    
    import java.util.Date;
    
    /**
     * 原型模式
     * 数据内容完全一样,但实例不同
     * 1. 能够直接拷贝其实际内容的数据类型/只支持9种,八大基本数据类型+String
     * 2. 深拷贝,其它类型也能拷贝
     */
    public class Test {
        public static void main(String[] args){
            ConcretePrototype cp = new ConcretePrototype();
            cp.setAge(11);
            cp.setName("abc");
            cp.list.add("hhhh");
            cp.setDate(new Date());
            try {
                ConcretePrototype clone = (ConcretePrototype) cp.clone();
                System.out.println(clone==cp);
                System.out.println(clone.list==cp.list);
                System.out.println(clone.getAge()+" "+clone.getName()+" "+clone.list.size());
                System.out.println(clone.getDate().getTime());
                System.out.println(cp.getDate().getTime());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    -------------------------------------------------

    package prototype.prototype;
    
    import java.util.Date;
    
    /**
     * 鸣人
     */
    public class MingRen {
        protected int height;
        protected Date date;
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    }
    
    package prototype.prototype;
    
    import java.io.Serializable;
    
    /**
     * 手里剑
     */
    public class ShouLiJian implements Serializable {
        private float height = 10;
    
        public void grow(){
            this.height *= 2;
        }
    
        public float getHeight() {
            return height;
        }
    }
    
    package prototype.prototype;
    
    import java.io.*;
    import java.util.Date;
    
    /**
     *
     */
    public class YingFenSheng extends  MingRen implements Cloneable, Serializable {
        private ShouLiJian shouLiJian;
    
        public YingFenSheng() {
            System.out.println("构造执行");
            this.shouLiJian = new ShouLiJian();
            this.height = 170;
            this.date = new Date();
        }
    
        @Override
        protected Object clone(){
            //深度克隆
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;
    
            try {
                //序列化
                //对象持久化
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);
                oos.writeObject(this);
                //反序列化
                bis = new ByteArrayInputStream(bos.toByteArray());
                ois = new ObjectInputStream(bis);
                YingFenSheng yingFenSheng = (YingFenSheng) ois.readObject();
                // 设置新的时间
                yingFenSheng.date = new Date();
    
                return yingFenSheng;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    if (bos!=null){
                        bos.close();
                    }
                    if (oos!=null){
                        oos.close();
                    }
                    if (bis!=null){
                        bis.close();
                    }
                    if (ois!=null){
                        ois.close();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            return null;
        }
    
        public void change(){
            YingFenSheng copy = (YingFenSheng)clone();
            System.out.println("mingren: "+this.date.getTime()+" "+copy.getHeight());
            System.out.println("copy: "+copy.getDate().getTime()+" "+copy.getHeight());
            System.out.println(this==copy);
            System.out.println(this.getShouLiJian()==copy.getShouLiJian());
            this.getShouLiJian().grow();
            System.out.println("------------");
            System.out.println("yuan ShouLiJian: "+this.getShouLiJian().getHeight());
            System.out.println("copy ShouLiJian: "+copy.getShouLiJian().getHeight());
        }
    
        public ShouLiJian getShouLiJian() {
            return shouLiJian;
        }
    
        public void setShouLiJian(ShouLiJian shouLiJian) {
            this.shouLiJian = shouLiJian;
        }
    }
    
    package prototype.prototype;
    
    /**
     *
     */
    public class Test {
        public static void main(String[] args){
            YingFenSheng yingFenSheng = new YingFenSheng();
            yingFenSheng.change();
        }
    //mingren: 1582682313951 0
    //copy: 1582682314078 0
    //false
    //false
    //------------
    //yuan ShouLiJian: 20.0
    //copy ShouLiJian: 10.0
    }
    

    克隆破坏单例模式

    如果我们克隆的目标的对象是单例对象,那意味着,深克隆就会破坏单例。实际上防止 克隆破坏单例解决思路非常简单,禁止深克隆便可。要么你我们的单例类不实现 Cloneable 接口;要么我们重写 clone()方法,在 clone 方法中返回单例对象即可,具体 代码如下:

    @Override
    protected Object clone() throws CloneNotSupportedException { 
        return INSTANCE;
    }
    

    ArrayList的Cloneable 源码

     /**
         * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
         * elements themselves are not copied.)
         *
         * @return a clone of this <tt>ArrayList</tt> instance
         */
        public Object clone() {
            try {
                ArrayList<?> v = (ArrayList<?>) super.clone();
                v.elementData = Arrays.copyOf(elementData, size);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
        }
    
  • 相关阅读:
    JDBI
    Concise: Compressed ’n’ Composable Integer Set
    java 7 新特性
    BIO的简单Demo
    手写一个死锁Demo
    实现一个Cglib代理Demo
    实现一个JDK代理demo
    ClassNotFoundException和 NoClassDefFoundError区别验证
    集合—ArrayList
    Hadoop之Storm基础
  • 原文地址:https://www.cnblogs.com/fly-book/p/10371532.html
Copyright © 2011-2022 走看看