五分钟精通设计模式之原型模式

本文详细介绍了原型模式的概念及其应用场景,对比了原型模式与直接new对象的性能差异,并通过具体实例展示了如何实现浅克隆与深克隆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

  • 原型模式(Prototype Pattern)是指原型实例指定创建对象的 种类,并且通过拷贝这些原型创建新的对象。
  • 调用者不需要知道任何创建细节,不调用构造函数。

适用场景

  • 类初始化消耗资源较多。
  • new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
  • 构造函数比较复杂
  • 循环体中生产大量对象时,可读性下降。
  • 原型模式就是快速构建对象的方法总结, 简单工厂将getter、setter封装到某个方法中 JDK提供的实现Cloneable接口,实现快速复制 scope=“prototype”,scope=”singleton”

优点

  • 原型模式性能比直接new一个对象性能高
  • 简化了创建过程

缺点

  • 必须配备克隆(或者可拷贝)方法
  • 对克隆复杂对象或对克隆出的对象进行复杂改造时,易带来风险
  • 深拷贝、浅拷贝要运用得当

实例

简单克隆

创建原型Prototype接口

public interface Prototype{
    Prototype clone();
}

创建具体需要克隆的对象ConCretePrototype

public class ConcretePrototypeA implements Prototype {
​
    private int age;
    private String name;
    private List hobbies;
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public List getHobbies() {
        return hobbies;
    }
​
    public void setHobbies(List hobbies) {
        this.hobbies = hobbies;
    }
​
    @Override
    public ConcretePrototypeA clone() {
        ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
        concretePrototype.setAge(this.age);
        concretePrototype.setName(this.name);
        concretePrototype.setHobbies(this.hobbies);
        return concretePrototype;
    }
​
}

创建client对象

public class Client {
​
    private Prototype prototype;
​
    public Client(Prototype prototype){
        this.prototype = prototype;
    }
    public Prototype startClone(Prototype concretePrototype){
        return (Prototype)concretePrototype.clone();
    }
​
}

测试实例

  // 创建一个具体的需要克隆的对象
        ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
        // 填充属性,方便测试
        concretePrototype.setAge(18);
        concretePrototype.setName("prototype");
        List hobbies = new ArrayList<String>();
        concretePrototype.setHobbies(hobbies);
        System.out.println(concretePrototype);
​
        // 创建Client对象,准备开始克隆
        Client client = new Client(concretePrototype);
        ConcretePrototypeA concretePrototypeClone = (ConcretePrototypeA) client.startClone(concretePrototype);
        System.out.println(concretePrototypeClone);
​
        System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getHobbies());
        System.out.println("原对象中的引用类型地址值:" + concretePrototype.getHobbies());
        System.out.println("对象地址比较:"+(concretePrototypeClone.getHobbies() == concretePrototype.getHobbies()));

运行结果

 

从测试结果看出 hobbies 的引用地址是相同的,意味着复制的不是值,而是引用的地址。 这 样 的 话 , 如 果 我 们 修 改 任 意 一 个 对 象 中 的 属 性 值 , concretePrototype 和 concretePrototypeCone 的 hobbies 值都会改变。这就是我们常说的浅克隆。只是完整 复制了值类型数据,没有赋值引用对象。

 

深度克隆

    ​    ​我们换一个场景,大家都知道齐天大圣。首先它是一只猴子,有七十二般变化,把一根毫毛就可以吹出千万个泼猴,手里还拿着金箍棒,金箍棒可以变大变小。这就是我们耳 熟能详的原型模式的经典体现。

创建猴子Monkey类

public class Monkey {
    public int height;
    public int weight;
    public Date birthday;
​
}

创建金箍棒类

public class JinGuBang implements Serializable {
    public float h = 100;
    public float d = 10;
​
    public void big(){
        this.d *= 2;
        this.h *= 2;
    }
​
    public void small(){
        this.d /= 2;
        this.h /= 2;
    }
}

创建对象齐天大圣类

public class QiTianDaSheng extends Monkey implements Cloneable,Serializable {
​
    public JinGuBang jinGuBang;
​
    public  QiTianDaSheng(){
        //只是初始化
        this.birthday = new Date();
        this.jinGuBang = new JinGuBang();
    }
​
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return this.deepClone();
    }
​
​
    public Object deepClone(){
        try{
​
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
​
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
​
            QiTianDaSheng copy = (QiTianDaSheng)ois.readObject();
            copy.birthday = new Date();
            return copy;
​
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
​
    }
​
​
    public QiTianDaSheng shallowClone(QiTianDaSheng target){
​
        QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
        qiTianDaSheng.height = target.height;
        qiTianDaSheng.weight = target.height;
​
        qiTianDaSheng.jinGuBang = target.jinGuBang;
        qiTianDaSheng.birthday = new Date();
        return  qiTianDaSheng;
    }

测试类

 QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
        try {
            QiTianDaSheng clone = (QiTianDaSheng)qiTianDaSheng.clone();
            System.out.println("深克隆:" + (qiTianDaSheng.jinGuBang == clone.jinGuBang));
        } catch (Exception e) {
            e.printStackTrace();
        }
​
        QiTianDaSheng q = new QiTianDaSheng();
        QiTianDaSheng n = q.shallowClone(q);
        System.out.println("浅克隆:" + (q.jinGuBang == n.jinGuBang));

运行结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值