原型模式详解

1.模式介绍

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

拷贝是原型模式的精髓所在。

2示例模型

记得上小学的时候,老师把需要做的课外习题写到黑板上,而下面的我们都要把这些题抄 写到自己的本子上,回家做好,第二天交上来,也就是每道题,全班50个人,每个人都要抄写一遍。按照现在的时间理论来说,就是浪费了50个人的时间。但是,那个时候条件限制,老师也是不得已而为之。现在好了,老师做一份电子版的习题,打印一份,然后拿着这份打印的原版,就可以复制出50份。

结合原型模式的概念进行分析,老师打印出来的那一份(已有的对象)就是“原型“,而复制出来的那50份,就是使用的“拷贝。而原型模式就是这么简单的一个道理,通过现有的东西,再复制出一个来。

3.应用场景

(1)新对象与原有对象区别小,只是某些属性不同,新的对象可以通过原型模式对已有对象进行复制来获得,再稍作修改。

(2)当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象。(直接使用复制构造函数需要知道对象的类型)

(3)程序运行过程,某个状态下需要一个对象副本,而对象属性有可能在运行过程改变,使用new来创建显然不适合,而且通过 new 产生一个对象需要非常繁琐的数据准备或访问权限。

4.角色结构分析

 

(1)抽象原型类(AbstractPrototype)规定了具体原型对象必须实现的接口

(2)具体原型类(ConcretePrototype)从抽象原型派生而来,是客户程序使用的,需要实现抽象原型角色所要求的接口

(3)客户(Client)客户调具体原型对象方法创建一个新的对象

5.应用案例:在已有邮件上修改生成需要发送的新邮件

#include <iostream>
#include <string.h>
using namespace std;
// 抽象原型类
class AbstractPrototype{
public:
    virtual AbstractPrototype* clone() = 0;
    virtual void show() = 0;
  
};

//附件类
class Attachment {
private:
    string nameAtt; /// 附件名
public:
    void changeName(const string& name) {
        nameAtt = name;
    };
    string getName() {
        return nameAtt;
    }
};
//具体原型类
class ConcretePrototypeMail : public AbstractPrototype {
private:
    string mailTitle;
    string mailSender;
    string mailRecipients;
    string mailBody;
    Attachment* mailAtta = NULL;
public:
    ConcretePrototypeMail(const string& title, const string& sender, const string& rec, const string& body, const string& nameAtt) {
        mailTitle = title;
        mailSender = sender;
        mailRecipients = rec;
        mailBody = body;
        if (!nameAtt.empty()) {
            mailAtta = new Attachment();
            mailAtta->changeName(nameAtt);
        }
    }
    ConcretePrototypeMail(const ConcretePrototypeMail& other) {
        this->mailTitle  = other.mailTitle;
        this->mailSender = other.mailSender;
        this->mailRecipients = other.mailRecipients;
        this->mailBody = other.mailBody;
        if (other.mailAtta != NULL) {
            mailAtta = new Attachment();
            mailAtta->changeName(other.mailAtta->getName());
        }
    }
    ~ConcretePrototypeMail(){
        if (mailAtta != NULL) {
            delete(mailAtta);
        }
    }
    virtual ConcretePrototypeMail* clone() {
        ConcretePrototypeMail* newMail = new ConcretePrototypeMail(*this);
        return newMail;
    }
    void show() {
        cout << "MailTitle: " << mailTitle << endl;
        cout << "MailSender: " << mailSender << endl;
        cout << "MailRecipients: " << mailRecipients << endl;
        cout << "MailBody: " << mailBody << endl;
        cout << "MailAttachment: " << mailAtta->getName() << endl;
    }
    void changeTitle(string title) {
        mailTitle = title;
    }
    void changeSender(string sender) {
        mailSender = sender;
    }
    void changeRecipients(string rec) {
        mailRecipients = rec;
    }
    void changeBody(string body) {
        mailBody = body;
    }
    void changeAtt(string name) {
        if (mailAtta != NULL) {
            delete(mailAtta);
        }
        mailAtta = new Attachment();
        mailAtta->changeName(name);
    }
};

int main() {
    //初始邮件创建
    ConcretePrototypeMail* originalMail = new ConcretePrototypeMail("original_title", "original_sender", "original_rec", "original_body", "original_attachment");
    cout << "====originalMail====" << endl;
    originalMail->show();
    // 深拷贝
    ConcretePrototypeMail* copyMail = originalMail->clone();
    copyMail->changeTitle("copymail_title");
    copyMail->changeSender("copymail_sender");
    copyMail->changeRecipients("copymail_rec");
    copyMail->changeBody("copymail_body");
    copyMail->changeAtt("copymail_attachment");
    cout << "====copyMail_A====" << endl;
    cout << "copyMail_A address: " << copyMail << endl;
    copyMail->show();
    cout << "====originalMail====" << endl;
    originalMail->show();
    delete originalMail;
    delete copyMail;
    return 0;
}

6.模式总结

优点:

(1)当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,提高新实例的创建效率。

(2)扩展性较好,模式中提供了抽象原型类,具体原型类可根据需要扩展。

缺点:

(1)需要为每一个类配备一个克隆方法,该克隆方法位于一个类的内部,改造已有类时需要修改源代码,违背开闭原则;

(2)在实现深克隆时需要编写较为复杂的代码,并且如果对象嵌套很多引用时,为了实现深拷贝每一层嵌套都必须支持深克隆。

注意事项:

(1)拷贝构造函数是核心,而且针对c++要进行的是深拷贝。

(2)克隆函数的关键就是调用拷贝构造函数。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值