装饰者模式(Decorator Pattern)

1. 何为装饰者模式?

不改变原有类的结构,动态地给其对象添加新功能。


2. 为什么需要装饰者模式?

面向对象编程原则之一:开闭原则

即开放扩展、关闭修改(不修改已有代码的情况下,通过扩展的方式增加新功能而满足需求的变化)。该原则旨在提高代码的复用性、可维护性,降低代码耦合度

于是就有了装饰者模式。


3. 详细说明+例子

开发过程中发现有新需求,需要增加原有类的功能,根据开闭原则,不允许直接修改原有类。

一种解决方式是:使用继承,在子类中添加新功能。

例子如下(例子中的黑色箭头表示继承,粉色箭头表示指针指向):

某汽车公司有两款车型:CarA和CarB,第一代CarA_1st和CarB_1st都只有各自的基础功能,如图1.

图1

现在公司为CarA、CarB增加新功能升级成第二代,两款车型都分别推出高配和低配,如图2.

图2

可见若通过继承的方式升级第二代车会导致子类过多,若第一代推出更多车型,则第二代会产生更多的子类。

显然该场景中,通过继承这种方式来添加新的功能并不好。

使用装饰者模式改进

做法是:

定义一个装饰者类继承自Car类,在其中定义Car类型指针成员pCar,因为Car为基类,所以该指针pCar可以指向其子类CarA_1st或者CarA_2st,从而获取其中的基础功能,然后在获取基础功能的基础上,可以添加新功能,即装饰,由此不改变原有类结构,同时大大减少子类数量。如图3所示。

图3


代码示例:

/* 抽象基类 */
class Car {
public:
    virtual void func() = 0;
private:
};

/* 第一代车 */
class CarA_1st : public Car {
public:
    virtual void func() {
        cout << "基础功能A" << endl;
    }
private:
};

class CarB_1st : public Car {
public:
    virtual void func() {
        cout << "基础功能B" << endl;
    }
private:
};

/* 装饰者类,用于创建第二代车 */
class CarDecoratorHigh : public Car {  // 第二代高配车
public:
    CarDecoratorHigh(Car* p) : pCar(p) {}

    virtual void func() {
        pCar->func();   // 将原有的基础功能拿过来
        cout << "高配功能" << endl;
    }
private:
    Car* pCar; // 基类指针,可指向派生类
};

class CarDecoratorLow : public Car {  // 第二代低配车
public:
    CarDecoratorLow(Car* p) : pCar(p) {}

    virtual void func() {
        pCar->func();   // 将原有的基础功能拿过来
        cout << "低配功能" << endl;
    }
private:
    Car* pCar; // 基类指针,可指向派生类
};

/* 测试 */
void test() {
    Car* pCarA_1st = new CarA_1st;  // 创建第一代CarA
    Car* pCarA_2nd_high = new CarDecoratorHigh(pCarA_1st);  // 使用装饰类将第一代CarA升级成第二代CarA高配版
    pCarA_2nd_high->func();
    delete pCarA_1st;
    delete pCarA_2nd_high;
}

为什么装饰类也要继承自基类呢?

结合图3和代码来看。

万一将来还有装饰类B在已有装饰类A基础上再装饰,若装饰类A不是Car的子类,则装饰类B无法使用Car*指针获得装饰类A的已有功能。 且若装饰类A不是Car的子类,则它就不能使用基类Car的虚函数func()来实现多态,也就不能在运行时动态地给原有对象添加额外的功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的马师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值