设计模式之5 -- 原型模式

原型模式学习笔记

通过一个原型对象克隆出多个一模一样的对象,该模式称之为原型模式。

定义:使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。

通过克隆所创建的对象是全新的对象,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法实现。

原型模式结构图 如下图所示:

在原型模式中包含如下几个角色:

抽象原型类,声明克隆方法的接口,是所有具体原型类的公共父类。

具体原型类:实现再抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。

class ConcreteProtoType implements ProtoType {
    private String attr;
    public void setAttr(String attr) {
        this.attr = attr;
    }

    public String getAttr() {
        return this.attr;
    }

    public ProtoType clone() {
        ProtoType protoType = new ConcreteProtoType();
        protoType.setAttr(this.attr);
        return protoType;
    }
}

在Java中对于所有的对象都是有一个共同父类Object的,而Object类已经声明了clone方法接口的,因为我们对于需要实现克隆方法的直接调用父类的clone方法就好,只需要在实现克隆类的时候实现Cloneable接口,即表示这个Java类支持被克隆。如下:

class ConcreteType implements Cloneable {
    ....
    public ProtoType clone() {
        Object object = null;
        try {
            object = super.clone();
        } catch (CloneNotSupportedException exception) {
            /*handle the exception*/
        }
        return (ProtoType)object;
    }
}

class Client {
    public static void main(String args[]) {
        ProtoType obj1 = new ConcreteProtoType();
        ProtoType obj2 = obj1.clone();
        /*此时obj1和obj2是完全相同的*/
    }
}

通过以上的方法就可以实现类的克隆。

但是在生产过程中发现如果类的成员含有的不只有基本类型的话,如果还含有其他类对象的话,就会导致问题。这里涉及到深拷贝和浅拷贝的概念。

对于浅拷贝,只是简单的将类的数据拷贝,即在内存中复制一份相同的数据而已,那如果还有别的类对象的话就会出现克隆类和原型类都含有对象的共同引用,而不是真正意义上的克隆。这里就需要是用深拷贝,即在克隆的时候对于每一个类成员变量都会进行递归的进行克隆,那么这时候克隆类里所有的内容都和原类的内容一样,但是地址完全不相同。

而为了实现深拷贝,那么克隆类就需要实现接口Serializable,即表明该Java类是支持深拷贝的(序列化)。代码如下:

class WeeklyLog implements Serializable {
    private Attachment attachment;
    private String name;

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public Attachment getAttachment() {
        return this.attachment;
    }

    public WeeklyLog deepClone throws RuntimeException {
        ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
        ObjectOutputStream out= new ObjectOutputStream(memoryBuffer);
        out.writeObject(this);

        ObjectInputStream in = new ObjectArrayInputStream(new ByteArrayOutputStream(memoryBuffer.toByteArray()));
        return (WeeklyLog)in.readObject();
    }
}

通过序列化的方式就可以实现所谓的深拷贝,克隆出来的数据内容都是一样的,但是对象的地址完全不一样。

另外有一种所谓的原型管理器的概念,即将系统中所有需要使用原型模式进行克隆的类都放入管理器,客户端调用的时候直接传入需要克隆的参数,管理器会根据参数克隆出新的对象返回。

总结:

当需要创建的对象消耗很大的资源,诸如初始化时间长或者需要网络资源/CPU资源等,那么这时候就可以考虑使用原型模式,使用一个原本就存在的对象直接进行复制得到,这样子可以很大的提高效率。如果系统中需要对某个对象的状态进行保存,那么这时候就可以使用原型模式。

为了实现原型模式,类必须实现Clone接口或者Serializable接口,对于深拷贝的话还得修改每一层类的深克隆,实现起来较麻烦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需通过显式的实例化过程。原型模式通过克隆(clone)已有对象来创建新对象,从而避免了使用传统的构造函数创建对象的开销。 在C++中,原型模式可以通过实现一个可克隆接口(通常称为原型接口)来实现。这个接口通常包含一个克隆方法,用于复制当前对象并返回一个新的副本。派生类可以实现这个接口来定义自己的克隆逻辑。 以下是原型模式的一般实现步骤: 1. 创建一个原型接口(或基类): ``` class Prototype { public: virtual Prototype* clone() const = 0; virtual void setAttributes(...) = 0; virtual void print() const = 0; }; ``` 2. 实现原型接口的具体类(或派生类): ``` class ConcretePrototype : public Prototype { private: // 在派生类中定义特定的属性 // ... public: Prototype* clone() const override { return new ConcretePrototype(*this); } void setAttributes(...) override { // 设置属性值 } void print() const override { // 打印属性值 } }; ``` 3. 在客户端代码中使用原型模式: ``` Prototype* original = new ConcretePrototype(); original->setAttributes(...); Prototype* clone = original->clone(); clone->print(); delete original; delete clone; ``` 通过使用原型模式,我们可以避免在每次创建对象时重复执行初始化的过程,提高了对象的创建效率。此外,原型模式还允许我们在运行时动态地添加或删除对象的属性,并通过克隆来创建新对象。 需要注意的是,在实现原型类时,需要确保所有成员变量都能正确地被拷贝(或克隆)。有时候可能需要自定义拷贝构造函数和赋值运算符来实现深拷贝,以避免浅拷贝带来的问题。 总结起来,原型模式通过克隆已有对象来创建新对象,提供了一种简单且灵活的对象创建方式。它适用于那些对象的创建过程比较复杂或开销较大的情况下。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值