原型模式

Prototype Pattern与单例模式Singleton Pattern的目的相反。

此模式旨在建立多个对象,并且让调用者不用重复的进行属性的setXxx操作,也不使用构造方法就能够建立一个新的对象。

也叫作对象的copy或者clone;Spring中<bean scope="prototype">就是原型模式。

关于对象的复制,有深浅之分。

浅拷贝也叫浅克隆,指原对象的属性与克隆出来的对象属性引用统一内存地址。原对象的属性被修改,

克隆出来的对象的属性也随之改变。

深拷贝(深克隆)则会建立一个全新的对象,二者互不干扰。

1、浅克隆

接口Person中定义了clone()方法,实现类Singer实现过程以及mian()测试代码如下:

package com.ldy.designpattern.prototypePattern.myCode;

import java.util.ArrayList;
import java.util.List;

public class Singer  implements Person, Serializable{

    private String name;
    private String address;
    private List songs;
    public List getSongs() {
        return songs;
    }
    public void setSongs(List songs) {
        this.songs = songs;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Singer(){}
    public Singer(String name,String address,List songs){
        this.name=name;
        this.address=address;
        this.songs=songs;
    }

    @Override
    public Person clone() {
        Singer singer=new Singer();
        singer.setName(this.name);
        singer.setAddress(this.address);
        singer.setSongs(this.songs);
        return singer;
    }

    public static void main(String[] args) {
        List songs=new ArrayList();
        songs.add("关于郑州的记忆");
        songs.add("忽然");
        songs.add("天空之城");
        songs.add("热河");
        Singer lizhi =new Singer("李志","南京",songs);
        System.out.println("原对象->"+lizhi);

        Person clone = lizhi.clone();
        System.out.println("克隆出的对象->"+clone);
        System.out.println(lizhi.getSongs()==((Singer) clone).getSongs());
        System.out.println(lizhi.getAddress()==((Singer) clone).getAddress());
        System.out.println(lizhi.getName()==((Singer) clone).getName());
    }
}

结果证实,两者对象不是同一个。但是属性引用自一处。

浅克隆出来的对象状态会随另一个对象改变。

2、深克隆

浅克隆的内存引用源自同一处。那我们避免引用自同一处,可以通过序列化反序列化来完成。

main()方法修改一下

public static void main(String[] args) throws Exception{
        List songs=new ArrayList();
        songs.add("关于郑州的记忆");
        songs.add("忽然");
        songs.add("天空之城");
        songs.add("热河");
        Singer lizhi =new Singer("李志","南京",songs);
        System.out.println("原对象->"+lizhi);

        //通过序列化的形式 clone新对象
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(lizhi);
        ByteArrayInputStream bis =new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois =new ObjectInputStream(bis);
        Singer clone = (Singer)ois.readObject();

        System.out.println("克隆出的对象->"+clone);
        System.out.println(lizhi.getSongs()==((Singer) clone).getSongs());
        System.out.println(lizhi.getAddress()==((Singer) clone).getAddress());
        System.out.println(lizhi.getName()==((Singer) clone).getName());
    }

结果证实序列化出来的对象不仅不同,连属性也不相同。

3、深克隆与浅克隆都属于原型模式。应用不同的场景,如果需要完全不同的对象就选择深克隆。

4、克隆模式破坏单例。

   如果我们把原型思想作用到单例模式上,那就会破坏单例模式。那如何防止呢?

  4.1、禁止或覆写clone()方法:JDK提供Cloneable接口,其实就是要求实现类里复写clone()方法。

    我们的代码里有clone()方法,等同于实现了此接口。所以为了保护单例模式,我们的单例类不实现Cloneable接口或者在 clone()方法中返回单例对象即可。

  4.2、序列化与反序列化应对方法:在我写的单例模式一文中,专门针对序列化有处理方案。就是重写readResolve()方法。https://blog.youkuaiyun.com/Dy_lee/article/details/88575055

5、JDK中原型模式的克隆源码:ArrayList 实现了Cloneable接口。源码我也看不太懂,但是我测试结果是深克隆模式。

    public static void main(String[] args) {
        ArrayList pers=new ArrayList();
        pers.add("李志");
        pers.add("朴树");
        pers.add("许巍");
        pers.add("郭德纲");
        pers.add("丹泽尔。华盛顿");
        
        ArrayList clone = (ArrayList)pers.clone();
        pers.remove(0);//原引用移除李志
        clone.remove(1);//克隆对象移除朴树
        System.out.println("原引用->"+pers);
        System.out.println("克隆引用->"+clone);
    }

结果显示,在两个对象都进行删除操作时互不影响,说明完全是两个对象。ArrayList的clone()属于深克隆模式。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值