C++设计模式(原型、代理、适配器、组合)

发布于:2024-12-06 ⋅ 阅读:(27) ⋅ 点赞:(0)

一、原型模式

1.定义

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

原型模式允许通过复制现有的对象来创建新对象,而不是通过实例化类来创建。这种方式可以避免创建重复的对象,从而提高性能和降低内存消耗。

 

2.组成

  • 抽象原型:声明可以克隆自身的接口。
  • 具体原型:继承自抽象原型,实现具体的克隆方法,必要时还需要自定义拷贝构造函数。
  • 客户端:通过原型创建新的实例。

 

3.示例

//蛋糕抽象类(原型类)
class Cake {
protected:
    string* name;
    double* price;
public:
    virtual Cake* clone() = 0;
    virtual void showInfo() = 0;
    virtual ~Cake() {}
};

//巧克力蛋糕(具体蛋糕类)
class ChocolateCake :public Cake {
public:
    ChocolateCake() {
        name = new string("Chocolate cake");
        price = new double(15.0);
    }
    ~ChocolateCake() {
            delete name;
            delete price;
    }
    ChocolateCake(const ChocolateCake& other) {
        name = new string(*other.name);
        price = new double(*other.price);
    }
    virtual Cake* clone() override {
        return new ChocolateCake(*this);
    }
    virtual void showInfo() override {
        cout << *name << " " << *price << "$" << endl;
    }
};

//水果蛋糕(具体蛋糕类)
class FruitCake :public Cake {
public:
    FruitCake() {
        name = new string("Fruit cake");
        price = new double(12.0);
    }
    ~FruitCake() {
        delete name;
        delete price;
    }
    FruitCake(const FruitCake& other) {
        name = new string(*other.name);
        price = new double(*other.price);
    }
    virtual Cake* clone() override {
        return new FruitCake(*this);
    }
    virtual void showInfo() override {
        cout << *name << " " << *price << "$" << endl;
    }
};

测试代码:

Cake* c1 = new ChocolateCake();
Cake* c2 = c1->clone();
Cake* c3 = new FruitCake();
Cake* c4 = c3->clone();
c1->showInfo();
c2->showInfo();
c3->showInfo();
c4->showInfo();
delete c1;
delete c2;
delete c3;
delete c4;

输出结果:

Chocolate cake 15$
Chocolate cake 15$
Fruit cake 12$
Fruit cake 12$

 

 

二、代理模式

1.定义

为其它对象提供一种代理以控制对这个对象的访问。

代理模式通过引入一个新的代理对象来间接访问原始对象,从而实现对原始对象的控制和管理,可以用于实现远程代理、虚拟代理、保护代理和智能指引等。

 

2.组成

  • 抽象主题:声明原始对象和代理对象的共同接口。
  • 具体主题:继承自抽象主题的原始对象,即客户端实际想要访问的对象。
  • 代理:继承自抽象主题,内部包含一个指向具体主题的指针,代理对象可以控制对具体主题的访问,也可以在访问前后执行额外的操作。

 

3.示例

//明星的工作(抽象主题)
class StarWork {
public:
    virtual void doWork() = 0;
    virtual ~StarWork() {}
};

//明星(具体主题)
class SingerStar :public StarWork {
public:
    virtual void doWork() override {
        cout << "歌手正在表演。" << endl;
    }
};

//经纪人(代理)
class StarAgent :public StarWork {
private:
    SingerStar* star;
    bool is_start;
public:
    StarAgent() :star(new SingerStar()), is_start(true) {}
    ~StarAgent() {
        delete star;
    }
    virtual void doWork() override {
        if (is_start) {
            cout << "经纪人谈好出场费、安排行程。" << endl;
            star->doWork();
            cout << "经纪人处理后续事务。" << endl;
        }
    }
};

测试代码:

StarAgent* agent = new StarAgent();
agent->doWork();
delete agent;

输出结果:

经纪人谈好出场费、安排行程。
歌手正在表演。
经纪人处理后续事务。

 

 

三、适配器模式

1.定义

将一个类的接口转换成客户希望的另一个接口。

Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

 

2.组成

  • 目标接口:客户期望使用的接口,也是适配器类需要实现的接口。
  • 适配者:定义一个已经存在的接口,这个接口需要适配。
  • 对象适配器:持有一个指向适配者的指针,将适配者的接口与目标接口进行适配。

 

3.示例

//目标接口,代表新的充电器接口
class NewCharger {
public:
    virtual void charge() = 0;
};

//适配者,代表旧款手机充电接口
class OldCharger {
public:
    void oldCharge() {
        cout << "Charging with old interface." << endl;
    }
};

//适配器,将旧接口适配到新接口
class Adapter :public NewCharger {
private:
    OldCharger* oldPhone;
public:
    Adapter(OldCharger* old) :oldPhone(old) {}
    virtual void charge() override {
        cout << "Using adapter to charge: " << endl;
        oldPhone->oldCharge();
    }
};

测试代码:

OldCharger* old_phone = new OldCharger();
Adapter* charger_dapter = new Adapter(old_phone);
charger_dapter->charge();
delete charger_dapter;
delete old_phone;

输出结果:

Using adapter to charge:
Charging with old interface.

 

 

四、组合模式

1.定义

将对象组合成树形结构,以表示“部分-整体”的层次结构。

组合模式使得用户对单个对象和组合对象的使用具有一致性,即客户端可以统一地处理单个对象和对象组合,而无需区分它们的具体类型。

 

2.组成

  • 抽象组件:定义组合对象和叶子对象的公共接口,用于访问和管理组件的子部件。
  • 叶子节点:表示树形结构中的最底层节点,它们没有子节点。
  • 组合节点:定义有枝节点行为,用来存储子部件并实现与其相关的操作,如增加和删除等。

 

3.示例

//组件接口(抽象节点)
class CompanyComponent {
public:
    CompanyComponent(const string& n) :name(n) {}
    virtual void display(int depth = 0) = 0;
    virtual int getEmployeeCount() = 0;
    virtual ~CompanyComponent() {}
protected:
    string name;
};

//员工(叶子节点)
class Employee :public CompanyComponent {
public:
    using CompanyComponent::CompanyComponent;
    virtual void display(int depth = 0) override {
        for (int i = 0; i < depth; i++)
            cout << " ";
        cout << "Emplyee: " << name << endl;
    }
    virtual int getEmployeeCount() override {
        return 1;
    }
};

//部门(组合节点)
class Department :public CompanyComponent {
private:
    list<shared_ptr<CompanyComponent>> children;
public:
    using CompanyComponent::CompanyComponent;
    void add(shared_ptr<CompanyComponent> p) {
        children.push_back(p);
    }
    void remove(shared_ptr<CompanyComponent> p) {
        children.remove(p);
    }
    virtual void display(int depth = 0) override {
        for (int i = 0; i < depth; i++)
            cout << " ";
        cout << "Department: " << name << endl;
        for (const auto& p : children)
            p->display(depth + 1);
    }
    virtual int getEmployeeCount() override {
        int cnt = 0;
        for (const auto& p : children)
            cnt += p->getEmployeeCount();
        return cnt;
    }
};

测试代码:

shared_ptr<Department> ceo = make_shared<Department>("CEO Office");
shared_ptr<Department> devDep = make_shared<Department>("Development Department");
shared_ptr<Employee> dev1 = make_shared<Employee>("Developer1");
shared_ptr<Employee> dev2 = make_shared<Employee>("Developer2");
shared_ptr<Employee> dev3 = make_shared<Employee>("Developer3");
devDep->add(dev1);
devDep->add(dev2);
devDep->add(dev3);
auto marDep = make_shared<Department>("Marketing Department");
auto mar1 = make_shared<Employee>("Marketer1");
marDep->add(mar1);

ceo->add(devDep);
ceo->add(marDep);
ceo->display();
cout << "Total employee count: " << ceo->getEmployeeCount() << endl << endl;

devDep->remove(dev2);
devDep->remove(dev3);
ceo->display();
cout << "Total employee count: " << ceo->getEmployeeCount() << endl;

输出结果:

Department: CEO Office
 Department: Development Department
  Emplyee: Developer1
  Emplyee: Developer2
  Emplyee: Developer3
 Department: Marketing Department
  Emplyee: Marketer1
Total employee count: 4

Department: CEO Office
 Department: Development Department
  Emplyee: Developer1
 Department: Marketing Department
  Emplyee: Marketer1
Total employee count: 2