设计模式-原型模式

现有一只羊tom,姓名为tom, 年龄为1,颜色为白色,请编写程序创建和tom羊属性完全相同的2只羊


1.传统方法

1.1 代码实现
public class Client { 
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    }
}
1.2 优缺点
  • 优点:
    • 好理解,易操作
  • 缺点:
    • 效率较低
    • 需要重新初始化对象,而不是动态地获得对象运行时的状态, 不够灵活

2.原型模式

2.1 概念
  • 指用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

  • 创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节

  • 通过将原型对象传给那个要发动创建的对象,该发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()

2.2 优缺点
  • 优点:
    • 创建新的对象比较复杂时,可利用原型模式简化对象的创建过程
    • 不用重新初始化对象,动态地获得对象运行时的状态
    • 如果原始对象发生变化(比如增加或减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
  • 缺点:
    • 在实现深克隆的时候可能需要比较复杂的代码
    • 需要为每一个类配备一个克隆方法(意味着对已有的类进行改造时需要修改其源代码,违背了OCP原则)
2.3 代码实现
public class Sheep implements Cloneable {
	...
        
    @Override
    protected Object clone(){
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}
public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        // 此时如果在Sheep类中增加一个属性(赋了默认值)
        // 如果使用传统方法则需要写为:
        // Sheep sheep2 = 
        //     new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor(),sheep.getAddress());
        Sheep sheep2 = (Sheep) sheep.clone();
        Sheep sheep3 = (Sheep) sheep.clone();
    }
}
2.3 应用场景

Spring中原型bean的创建,就是原型模式的应用

// beans.xml
<bean id="emp" class="com.psj.emp" scope="prototype"/>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object bean = applicationContext.getBean("emp");

3.浅拷贝和深拷贝

3.1 浅拷贝
  • 对于基本数据类型的成员变量,浅拷贝会直接进行值传递(即将该属性值复制一份给新的对象)

  • 对于引用数据类型的成员变量,浅拷贝会进行引用传递(即只将该成员变量的内存地址复制给新对象)。一个对象修改该成员变量会影响到另一个对象的该成员变量值

  • 浅拷贝是使用默认的clone()方法来实现(2中的拷贝就是浅拷贝)

3.2 深拷贝
  • 复制对象的所有基本数据类型的成员变量值

  • 为引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象

  • 实现方式:

    • 重写clone方法:对引用数据类型单独调用clone方法
    public class DeepProtoType implements Serializable, Cloneable {
    
        public String name;  // String属性
        public DeepCloneableTarget deepCloneableTarget;  // 引用类型(该类中的属性都是基本数据类型了)
    
        public DeepProtoType() {}
    
        // 重写clone 方法
        @Override
        protected Object clone() throws CloneNotSupportedException {
    
            Object deep = null;
            // 完成对基本数据类型和String的克隆
            deep = super.clone();
            // 对引用类型的属性进行单独处理
            DeepProtoType deepProtoType = (DeepProtoType) deep;
            deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
    
            return deepProtoType;
        }
    }
    
    • 对象序列化(推荐):
    public class DeepProtoType implements Serializable, Cloneable {
    
        public String name;  // String属性
        public DeepCloneableTarget deepCloneableTarget;  // 引用类型
    
        public DeepProtoType() {
        }
    
        // 通过对象的序列化实现
        public Object deepClone() {
            // 创建流对象
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;
    
            try {
                // 序列化
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);
                oos.writeObject(this);  // 当前这个对象以对象流的方式输出
    
                // 反序列化
                bis = new ByteArrayInputStream(bos.toByteArray());
                ois = new ObjectInputStream(bis);
                DeepProtoType copyObj = (DeepProtoType) ois.readObject();
    
                return copyObj;
    
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                // 关闭流
                try {
                    bos.close();
                    oos.close();
                    bis.close();
                    ois.close();
                } catch (Exception e2) {
                    System.out.println(e2.getMessage());
                }
            }
    
        }
    }
    
    public class Client {
        public static void main(String[] args) throws Exception {
            DeepProtoType p = new DeepProtoType();
            p.name = "psj";
            p.deepCloneableTarget = new DeepCloneableTarget("psj1", "psj2");
    
            // 重写clone方法
            DeepProtoType p2 = (DeepProtoType) p.clone();
            // 两个hashcode不一样
            System.out.println(p.deepCloneableTarget.hashCode());
            System.out.println(p2.deepCloneableTarget.hashCode());
    
            // 对象序列化
            DeepProtoType p3 = (DeepProtoType) p.deepClone();
            // 两个hashcode不一样
            System.out.println(p.deepCloneableTarget.hashCode());
            System.out.println(p3.deepCloneableTarget.hashCode());
        }
    }
    

参考

https://www.bilibili.com/video/BV1G4411c7N4?p=49-54


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值