第六章 原型模式(克隆)

快速导航
一、代码示例(浅克隆、深克隆)
二、克隆方式破坏单例模式
三、jdk中使用原型模式
原型模式介绍

定义:原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
不需要知道任何创建的细节,不调用构造函数。
类型:创建型

适用场景:

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

优点:
简化创建过程
性能比new 一个对象性能高

缺点:
必须配备克隆方法
对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
深拷贝、浅拷贝要运用得当(深克隆还需要对某些属性做修改)

一、代码示例(浅克隆、深克隆)
/**
 * @program: adpn-pattern->Computer
 * @description: 电脑实例
 * @author: Jstar
 * @create: 2019-11-24 11:58
 **/
public class Computer implements Cloneable{

    private String name;
    private String software;
    private Date createTime;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public Computer(String name, String software, Date createTime) {
        this.name = name;
        this.software = software;
        this.createTime = createTime;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSoftware() {
        return software;
    }
    public void setSoftware(String software) {
        this.software = software;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    @Override
    public String toString() {
        return "Computer{" +
                "name='" + name + '\'' +
                ", software='" + software + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

//测试类
public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(0L);
        Computer computer1 = new Computer("联想", "win7", date);
        Computer computer2 = (Computer) computer1.clone();
        System.out.println(computer1);
        System.out.println(computer2);
        System.out.println(computer1==computer2);
    }
}

看一下运行结果:
在这里插入图片描述
虽然toString 值相同,但是这两个却不是一个对象。

// 测试改变 computer1 的 createTime
在这里插入图片描述
结果是 computer2 的 createTime 也改变了。

Debug 查看一下:
在这里插入图片描述

虽然computer1 和 computer2对象不同,但 引用型对象 createTime 却指向同一个地址,这就是导致他们 createTime 相同的原因。 这种就是浅拷贝。

如何能做到 createTime 也不同呢,也就是深拷贝解决的问题。我们来改一下 Computer 的 clone() 方法。

@Override
    protected Object clone() throws CloneNotSupportedException {
        Computer computer = (Computer) super.clone();
        computer.createTime= (Date) computer.getCreateTime().clone();
        return computer;
    }

测试一下:
在这里插入图片描述
在这里插入图片描述
引用类型变量也不再是同一个地址,这样就实现了深克隆。

二、克隆方式破坏单例模式

代码:

/**
 * @program: adpn-pattern->HungrySinglon
 * @description: 饿汉式单例模式
 * @author: Jstar
 * @create: 2019-11-23 11:12
 **/
public class HungrySinglon implements Serializable,Cloneable {
    private final static HungrySinglon hungrySinglon=new HungrySinglon();
    private HungrySinglon(){
        if(hungrySinglon!=null){
            throw new RuntimeException("不允许使用私有构造器创建对象");
        }
    }

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

    public static HungrySinglon getInstance(){
        return hungrySinglon;
    }
    public Object  readResolve(){
        return hungrySinglon;
    }
}
/**
 * @program: adpn-pattern->HungryCloneTest
 * @description: 演示克隆破坏单例模式
 * @author: Jstar
 * @create: 2019-11-24 15:51
 **/
public class HungryCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        HungrySinglon instance = HungrySinglon.getInstance();

        Class<HungrySinglon> hungrySinglonClass = HungrySinglon.class;
        Method clone = hungrySinglonClass.getDeclaredMethod("clone");
        clone.setAccessible(true);
        HungrySinglon instance2 = (HungrySinglon) clone.invoke(instance);

        System.out.println(instance);
        System.out.println(instance2);
    }
}

运行结果:

在这里插入图片描述
单例模式已被 反射和克隆破坏了。

如果是这种情况,怎么保证单例呢。
解决方法有2个:
1、单例实例不继承 Cloneable,不重写 clone()方法。
2、在克隆方法内返回单例实体。即:

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

这样创建的单例对象就是同一个了。
在这里插入图片描述

三、jdk中使用原型模式

1、ArrayList实现了 Cloneable 接口:

在这里插入图片描述
在这里插入图片描述
是通过 Arrays.copyOf() 进行数据的克隆,实现是System.arraycopy()。

2、HashMap实现了 Cloneable 接口:

在这里插入图片描述
在这里插入图片描述

其它实现 Cloneable接口的类还是非常多的,有兴趣可以自己看一下。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值