Pattern(笔记) - 原型模式

原型模式

本篇文章是通过看视频学习总结的内容, 如有错误的地方请谅解,并联系博主及时修改,谢谢您的阅读.

何为原型模式?

原型模式可以客观的理解为对象的复制,通过原型模式对原有对象进行复制,对象的复制分为浅克隆深克隆

适用场景:

  1. 对象初始化资源比较多
  2. new 关键字创建对象过程复杂
  3. 构造函数逻辑复杂
  4. 循环过程中创建大量的对象

原型模式的优点:

  • 通过原型模式创建的对象不需要再次走 new 关键字,走构造函数去创建对象,而是直接 copy 内存中的内容,所以性能很高
  • 不走构造函数,完美避开了构造函数的约束

原型模式的缺点:

  • 被拷贝的对象中存在对象引用的情况,被引用的对象也需要实现 java.io.Serializable
  • 必须实现 java.lang.Cloneable 接口

举个例子:

  • 浅克隆实体类
@Setter
@Getter
@ToString
public class ShallowClone implements Serializable,Cloneable {
    private String username;
    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            return clone;
        } catch (Exception ex) {
            return null;
        }
    }
}

  • 浅克隆(对象中存在引用,则无法对引用的对象进行拷贝)
public static void main(String[] args) {
        ShallowClone shallowClone = new ShallowClone();
        shallowClone.setUsername("张三");

        ShallowClone clone = (ShallowClone)shallowClone.clone();
        clone.setUsername("李四");

		// 张三
        System.out.println(shallowClone);
        // 李四
        System.out.println(clone);
    }
  • 浅克隆对象中加入其他对象的引用
@Setter
@Getter
@ToString
public class ShallowClone implements Serializable, Cloneable {
    private String username;
    // 加入对象的引用
    List<String> hobbys;

    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            return clone;
        } catch (Exception ex) {
            return null;
        }
    }
}
  • 浅克隆加入对象引用
public static void main(String[] args) {
        ShallowClone shallowClone = new ShallowClone();
        shallowClone.setUsername("张三");
        List<String> hobbys = new ArrayList<>();
        hobbys.add("唱");
        hobbys.add("跳");
        hobbys.add("rap");
        hobbys.add("篮球");
        shallowClone.setHobbys(hobbys);

        ShallowClone clone = (ShallowClone)shallowClone.clone();
        clone.setUsername("李四");
        List<String> cloneHobbys = clone.getHobbys();
        cloneHobbys.add("蔡徐坤");

		// ShallowClone(username=张三, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
        System.out.println(shallowClone);
        // ShallowClone(username=李四, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
        System.out.println(clone);
    }
  • 通过浅克隆对象中加入对象引用,最终被引用的结果是一样的,可以分析得到实现java.lang.Cloneable 接口只是对对象进行了浅克隆,并非进行对象深克隆,如果被克隆的对象中存在其他对象的引用的时候,那么被克隆出来的值和原来的值是一致的,且内存地址也是相同的,那么被克隆的引用是直接复制了对象的地址,而不是对象中的内容。
  • 深克隆
@Setter
@Getter
@ToString
public class DeepEntity implements Cloneable, Serializable {

    private String userName;

    private String password;

    private List<String> phone;

    /**
     *  序列化和反序列化深克隆
     *  性能低, 占用IO,
     *
     * @return
     */
    public DeepEntity serializationDeepClone (){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (DeepEntity)ois.readObject();
        }catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     *  FastJson 序列化和反序列化深克隆
     *  对象中的对象无法实例化
     *
     * @return
     */
    public DeepEntity JsonDeepClone (){
        String json = JSON.toJSONString(this);
        return JSON.parseObject(json, DeepEntity.class);
    }


    /**
     * 使用spring-framework 工具类实现深克隆
     * @return
     */
    public DeepEntity beanUtilDeepClone() {
        DeepEntity deepEntity = new DeepEntity();
        BeanUtil.copyProperties(this, deepEntity, true);
        return deepEntity;
    }
}
  • 测试三种深克隆方法
package com.example.learn.design.patterns.prototype;

import com.example.learn.design.patterns.prototype.deep.DeepEntity;
import com.example.learn.design.patterns.prototype.shallow.Entity;
import com.example.learn.design.patterns.prototype.shallow.ShallowClone;

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

/**
 * 深克隆测试类
 * @author zyred
 * @createTime 2020/8/27 16:19
 **/
public class PrototypeClient {

    public static void main(String[] args) {
        deepClone ();
    }
    /**
     * 浅克隆
     */
    public static void deepClone (){
        DeepEntity entity = new DeepEntity();
        entity.setPassword("123456");
        entity.setUserName("zyred");
        
        List<String> hobbys = new ArrayList<>();
        hobbys.add("唱");
        hobbys.add("跳");
        hobbys.add("rap");
        hobbys.add("篮球");
        entity.setHobbys(hobbys);

        DeepEntity clone = entity.serializationDeepClone();
        //DeepEntity clone = entity.JsonDeepClone();
        //DeepEntity clone = entity.beanUtilDeepClone();
        clone.getHobbys().add("蔡徐坤");

		//DeepEntity(userName=zyred, password=123456, hobbys=[唱, 跳, rap, 篮球])
        System.out.println("entity: " + entity);
        //DeepEntity(userName=zyred, password=123456, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
        System.out.println("clone: " + clone);
		
		// false
        System.out.println(entity.getHobbys() == clone.getHobbys());
    }
}

总结:

  • 浅克隆是无法克隆对象中被引用的对象,只会复制引用的地址
  • 深克隆是对整个对象中的内容无死角的复制,而不是复制引用的地址,在工作中建议适用深拷贝。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值