设计模式之原型模式

1.介绍

  • 原型模式(Prototype)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  • 原型模式时一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
  • 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()

2.克隆羊实例

实例描述

  • 创建多个克隆养(Sheep)实例

利用new方式创建Sheep实例

  • Sheep

    public class Sheep {
    
        private String name;
        private int age;
    
        public Sheep(String name,int age){
            this.name=name;
            this.age=age;
        }
    }		
    
  • Client

    public class Client {
        public static void main(String[] args) {
            Sheep sheep1 =new Sheep("name1",1);
            Sheep sheep2 =new Sheep("name2",2);
            Sheep sheep3 =new Sheep("name3",3);
    
    
            System.out.println(sheep1.hashCode());
            System.out.println(sheep2.hashCode());
            System.out.println(sheep3.hashCode());
        }
    }
    
  • 执行结果

    460141958
    1163157884
    1956725890
    
  • 传统方法分析
    1) 优点:比较好理解,简单易操作
    2)在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
    3)总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活

  • 改进思路
    利用Java中Object跟类中的clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力

使用原型模式创建Sheep实例

  • Sheep
    克隆的类需要实现Cloneable接口,并重写clone()

    public class Sheep implements Cloneable {
    
        private String name;
        private int age;
    
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
        	//使用默认的clone方法进行浅拷贝
            Sheep sheep = (Sheep) super.clone();
            return sheep;
        }
    }	
    
  • Client

    public class Client {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Sheep sheep1 =new Sheep("name1",1);
            Sheep sheep2 = (Sheep) sheep1.clone();
            Sheep sheep3 = (Sheep) sheep1.clone();
            
            System.out.println(sheep1.hashCode());
            System.out.println(sheep2.hashCode());
            System.out.println(sheep3.hashCode());
        }
    }
    
  • 执行结果

    460141958
    1163157884
    1956725890
    

3.浅拷贝和深拷贝

3.1浅拷贝

1)对于数据类型是基于数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象
2)对于数据类型是引用数据类型的成员变量,比如成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的改成员变量值
3)浅拷贝是使用默认的clone()方法来实现
4)克隆羊方式采用的是浅拷贝方式

3.2深拷贝

介绍

1)复制对象的所有基本数据类型的成员变量值
2)为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说:对象进行深拷贝要对整个对象进行拷贝
3)深拷贝实现方式1:重写clone方法来实现深拷贝
4)深拷贝实现方式2:通过对象序列化实现深拷贝,该方法需要实现Serializable接口

代码实现

深拷贝方式1:重写clone方法
  • DeepSheep
    需要实现Cloneable,并重写cloene()方法

    public class DeepSheep implements Cloneable {
        private String address;
        private Sheep sheep;  //引用类型属性
    
        public DeepSheep(String address, Sheep sheep) {
            this.address = address;
            this.sheep = sheep;
        }
    
        public Sheep getSheep() {
            return sheep;
        }
    
        public String getAddress() {
            return address;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            //完成对基本数据类型(属性)的克隆
            DeepSheep deepSheep = (DeepSheep) super.clone();
            //对引用类型的属性,进行单独处理
            //调用sheep的clone()对Sheep克隆
            deepSheep.sheep = (Sheep) sheep.clone();
            return deepSheep;
        }
    }	
    
  • Client

    public class Client {	
    
        public static void main(String[] args) throws CloneNotSupportedException {
            DeepSheep deepSheep =new DeepSheep("address",new  Sheep("原始羊",100) );
            DeepSheep deepSheepClone= (DeepSheep) deepSheep.clone();
            deepSheepClone.getSheep().setName("克隆羊");
            System.out.println(deepSheep.hashCode()+" "+deepSheep.getAddress()+" "+deepSheep.getSheep().toString()+" "+deepSheep.getSheep().hashCode());
            System.out.println(deepSheepClone.hashCode()+" "+deepSheepClone.getAddress()+" "+deepSheepClone.getSheep().toString()+" "+deepSheepClone.getSheep().hashCode());
        }
    }	
    
  • 运行结果

    460141958 address name:原始羊,age:100 1163157884
    1956725890 address name:克隆羊,age:100 356573597	
    
深拷贝方式2:通过对象序列化
  • DeepSheep
    DeepSheep与Sheep都需要实现Serializable接口

    public class Sheep implements Serializable {
    }
    
    public class DeepSheep implements  Serializable {
        private String address;
        private Sheep sheep;  //引用类型属性
    
        public DeepSheep(String address, Sheep sheep) {
            this.address = address;
            this.sheep = sheep;
        }
    
        public Sheep getSheep() {
            return sheep;
        }
        
        public String getAddress() {
            return address;
        }
    
        /**
         * 采用序列化方式深拷贝
         *
         * @return
         */
        public DeepSheep deepClone() {
            //创建流对象
            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);
                DeepSheep deepSheepCopy = (DeepSheep) ois.readObject();
                return deepSheepCopy;
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            } finally {
                try {
                    bos.close();
                    oos.close();
                    bis.close();
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  • Client

    public class Client {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            DeepSheep deepSheep = new DeepSheep("address", new Sheep("原始羊1", 100));
            DeepSheep deepSheepClone = deepSheep.deepClone();
            deepSheepClone.getSheep().setName("克隆羊2");
            System.out.println(deepSheep.hashCode() + " " + deepSheep.getAddress() + " " + deepSheep.getSheep().toString() + " " + deepSheep.getSheep().hashCode());
            System.out.println(deepSheepClone.hashCode() + " " + deepSheepClone.getAddress() + " " + deepSheepClone.getSheep().toString() + " " + deepSheepClone.getSheep().hashCode());
            
    	    }
    }
    
  • 运行结果

    1836019240 address name:原始羊1,age:100 1265094477
    363771819 address name:克隆羊2,age:100 2065951873
    

    深拷贝方式1和方式2比较:方式2无须知道属性有多少引用类型属性,比较方便

4.事项与细节

1)创建新的对象比较复杂时,可以利用原型模式简单对象的创建过程,同时也能够提高效率
2)不用重新初始化对象,而是动态地获得对象运行时的状态
3)如果原始对象发送变化(增加或者减少属性),对其克隆对象的也会发生相应的变化,无需修改代码
4)在实现深克隆的时候可能需要比较复杂的代码
5)缺点: 需要为每个类配备一个克隆方法,这对新增的类不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值