设计模式之原型模式和浅拷贝,深拷贝

原型模型

原型模型是一种创建型(为了合理创建对象而设计的模式)的设计模型,,用来处理代码中,复制对象的操作。Spring 中原型 bean 的创建,就是原型模式的应用

不使用原型模型设计模式

  Pet pet=new Pet("小虎","22");//一个普通对象
     //企图复制10个pet,通过get例子中的属性,调用构造方法
     Pet pet1=new Pet(pet.getName(),pet.getAge());   
     Pet pet2=new Pet(pet.getName(),pet.getAge());   
     Pet pet3=new Pet(pet.getName(),pet.getAge());   
     Pet pet4=new Pet(pet.getName(),pet.getAge());   
     Pet pet5=new Pet(pet.getName(),pet.getAge());   
     Pet pet6=new Pet(pet.getName(),pet.getAge());   
     Pet pet7=new Pet(pet.getName(),pet.getAge());   
     Pet pet8=new Pet(pet.getName(),pet.getAge()); 

可以发现多次get属性,一旦属性多了,就会出现很多重复的代码,同时也会造成混乱。

使用原型模式
1.原型类实现克隆接口(就是相当于开启复制的功能)


```java
public class Pet implements Cloneable {
    private String name;
    private String age;

2.重写一个clone()方法,这是Object类的方法(所有类都直接或者间接继承Object类)

 @Override
    protected Object clone(){
        Pet p=null;
        try{
            p=(Pet) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }

3.直接调用clone()克隆方法

 Pet pet=new Pet("小虎","22");//一个普通对象
        
        //直接调用Pet的clone方法
        Pet pet1=(Pet) pet.clone();
        Pet pet2=(Pet) pet.clone();
        Pet pet3=(Pet) pet.clone();
        Pet pet4=(Pet) pet.clone();
        Pet pet5=(Pet) pet.clone();
        Pet pet6=(Pet) pet.clone();
        Pet pet7=(Pet) pet.clone();
        Pet pet8=(Pet) pet.clone();
        Pet pet9=(Pet) pet.clone();
  1. 创建新的对象比较复杂的时候,可以利用原型模式简化对象的创建,同时也能提高效率
  2. 不用重新初始化对象,而是动态地获得对象运行时状态
  3. 如果原始对象发生变化(增加或者删除了属性),其他地克隆对象也会相应地发生变化,无需修改代码
  4. 在实现深拷贝的时候,可能会需要比较复制的代码
  5. 缺点:需要为每个类配备一个克隆方法,这对全新的类影响不大,但是对于旧的类,需要修改代码,违反了ocp原则。

深浅拷贝讲解

深浅拷贝:拷贝的深浅针对于引用类型(不包含基本数据类型和String)拷贝而来的对象的对象字段是独立的,例如,一个Person对象的pet宠物属性(宠物也是一个对象),如果以Person A为原型拷贝出了Person B,那么深拷贝的情况下,A.petB.pet(为false),也就是两个宠物对象的地址是不一样的,而浅拷贝的情况下,A.petB.pet(为true,也就是A宠物和B的宠物实际上是同一个宠物,修改其中一个宠物就会影响到另一个宠物。

浅拷贝示例:

 Pet pet=new Pet("小狗","11");
        Person p1=new Person("小菜",pet);//小菜,小狗
        Person p2= (Person) p1.clone();//小菜,小狗
        p2.getPet().setName("小虎");
        Person p3= (Person) p1.clone();//小菜,小虎
        System.out.println("p1-------"+p1.getPet());//Pet{name='小虎', age='11'}
        System.out.println("p2------"+p2.getPet());//Pet{name='小虎', age='11'}
        System.out.println("p3-------"+p3.getPet());//Pet{name='小虎', age='11'}
        System.out.println("p1-------"+p1.getPet().hashCode());//356573597
        System.out.println("p2-------"+p2.getPet().hashCode());//356573597
        System.out.println("p3--------"+p3.getPet().hashCode());//356573597

可以发现p2的宠物进行了修改,影响到了p1的宠物。

深拷贝示例

 Pet pet=new Pet("小狗","22");
        Person p1=new Person("小擦",pet);

        Person p2=(Person) p1.clone();

        p2.getPet().setName("大笨蛋");
        Person p3=(Person) p1.clone();

        System.out.println(p1);//小狗 22
        System.out.println(p2);//大笨蛋 22
        System.out.println(p3);//小狗 22

可以发现修改了p2 并没有影响到p1

深拷贝的实现方法2:
通过对象序列化的方式,对象序列化是一种持久化对象的技术。先将源对象进行序列化,然后再从另一个位置对序列化的对象进行反序列化,最后间接完成复制。

 protected Object clone() throws CloneNotSupportedException {

        Object person=null;

        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        try {
            ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);//直接调用对象流来序列该对象,序列化到数组输出流中
        } catch (IOException e) {
            e.printStackTrace();
        }
        ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        //创建一个数组输入流,从上面的数组输出流中的数据
        try {
            ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);//用对象输入流承载数组输入流的数据
            person=(Person)objectInputStream.readObject();//直接对象输入流之中获取对象
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        finally {
            try {
                byteArrayOutputStream.close();
                byteArrayInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return person;
    }

以上是重写的clone方法
测试

  Pet pet=new Pet("小狗","22");
        Person p1=new Person("小擦",pet);

        Person p2=(Person) p1.clone();

        p2.getPet().setName("大笨蛋");
        Person p3=(Person) p1.clone();

        System.out.println(p1);//小狗 22
        System.out.println(p2);//大笨蛋 22
        System.out.println(p3);//小狗 22
        System.out.println(p1.getPet().hashCode());//692404036
        System.out.println(p2.getPet().hashCode());//867859325
        System.out.println(p3.getPet().hashCode());//553976328

可以发现篇p2修改宠物对象并不影响 p1对象的宠物。而且3个对象的宠物对象的hashcode都不一样!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值