原型模式

原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据

在这里插入图片描述

为什么使用原型模式

一个我们项目中经常会遇到的场景:通过数据库获取了一个对象A,这个对象的值会展示在页面上,并会根据页面的输入改变某些值。但这个对象A的原值我们需要保存,这时候我们就需要复制一个和A一样的B对象,用来展示和接收页面的值,使得A对象的值不受影响

class Human implements Cloneable {
    String humanName;
    String humanSex;
    String humanAge;
    public Human() {
    }
    public Human(String humanName, String humanSex, String humanAge) {
        this.humanName = humanName;
        this.humanSex = humanSex;
        this.humanAge = humanAge;
    }
    @Override
    public String toString() {
        return "human{" +
                "humanName='" + humanName + '\'' +
                ", humanSex='" + humanSex + '\'' +
                ", humanAge='" + humanAge + '\'' +
                '}';
    }
    public Human clone() {
        Human human = null;
        try {
            //调用Object类的clone方法,使用这个方法的对象需要实现Cloneable接口
            human = (Human) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return human;
    }
}
public class PrototypeDemo {
    public static void main(String[] args) {
        Human human1 = new Human("John", "Man", "23");
        Human human2 = human1.clone();
        //确认是否获取了原对象的所有值
        System.out.println(human2.toString());
        //确认是否是一个新的对象
        System.out.println(human2.hashCode() == human1.hashCode());
    }
}

上面代码有一个潜在的问题,Object类的clone方法对于拷贝的解释是,如果属性是基本数据类型它会把值复制过去,但属性如果是一个引用数据类型,它会把对应的地址复制过去,也就是说两个不同对象的属性指向了同一个引用,这就是浅拷贝。很多时候这种浅拷贝并不能满足我我们的需求,所有就有了深拷贝:利用序列化来复制对象

    public Human deepClone() {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInput = null;
        try {
            //序列化
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            //反序列化
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInput = new ObjectInputStream(byteArrayInputStream);
            Human human = (Human) objectInput.readObject();
            return human;
        } catch (Exception e) {
            System.out.println(e);
            return null;
        } finally {
            //错误的关闭流连接
            try {
                objectInput.close();
                byteArrayInputStream.close();
                objectOutputStream.close();
                byteArrayOutputStream.close();
            } catch (Exception e2) {
            }
        }
    }

序列化反序列化的方式有很多种,使用JSON也可以完成,包括很多第三方库也提供类似的功能。感觉这个原型模式使用的不是很频繁,不过在Spring中规定类的作用范围(scope)中有原型模式。上文中对于流的关闭采取了最简单的方式,这种方式也是有风险的:关闭流出错会造成流的关闭不完全。后面会介绍关闭流的正确姿势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值