装饰器设计模式学习

来自chatgpt

1.介绍

装饰器设计模式(Decorator Pattern)是一种结构型设计模式,允许你通过将对象包装在一个装饰器类中来动态地为对象添加新的功能。装饰器模式通常用于当需要扩展一个类的功能时,而不需要修改该类的源代码。它通过创建一个装饰器类来实现这一目标,并且可以将多个装饰器链式组合

装饰器模式的关键组成部分:

  1. Component(组件): 一个接口或抽象类,定义了被装饰对象的标准行为。
  2. ConcreteComponent(具体组件): 实现了Component接口的具体类,表示被装饰的对象。
  3. Decorator(装饰器): 一个实现了Component接口的抽象类,它持有一个Component对象并委托所有行为给它
  4. ConcreteDecorator(具体装饰器): 装饰器类的具体实现,它在调用委托的行为之前或之后执行额外的功能。

例子:

#include <iostream>
#include <string>

// Component接口
class Car {
public:
    virtual ~Car() = default;
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

// ConcreteComponent:基础的Car类
class BasicCar : public Car {
public:
    std::string getDescription() const override {
        return "Basic Car";
    }

    double cost() const override {
        return 20000.0;
    }
    ~BasicCar(){
        std::cout << "Deleting BasicCar" << std::endl;
    }
};

// Decorator基类,需要继承Car类
class CarDecorator : public Car {
protected:
    Car* car;
public:
    CarDecorator(Car* c) : car(c) {}
    virtual ~CarDecorator() { 
        std::cout << "Deleting CarDecorator" << std::endl;
        delete car; 
    }
};

// ConcreteDecorator:添加空调功能
class WithAirConditioning : public CarDecorator {
public:
    WithAirConditioning(Car* c) : CarDecorator(c) {}

    std::string getDescription() const override {
        return car->getDescription() + " with Air Conditioning";
    }

    double cost() const override {
        return car->cost() + 1500.0;
    }
    ~WithAirConditioning() {
        std::cout << "Deleting WithAirConditioning" << std::endl;
    }
};

// ConcreteDecorator:添加天窗功能
class WithSunroof : public CarDecorator {
public:
    WithSunroof(Car* c) : CarDecorator(c) {}

    std::string getDescription() const override {
        return car->getDescription() + " with Sunroof";
    }

    double cost() const override {
        return car->cost() + 1200.0;
    }
    ~WithSunroof() {
        std::cout << "Deleting WithSunroof" << std::endl;
    }
};

int main() {
    Car* myCar = new BasicCar();
    std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;

    myCar = new WithAirConditioning(myCar);
    std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;

    myCar = new WithSunroof(myCar);
    std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;

    delete myCar; // 删除装饰器时会自动删除基本车对象
    return 0;
}

// 运行结果
Basic Car costs $20000
Basic Car with Air Conditioning costs $21500
Basic Car with Air Conditioning with Sunroof costs $22700
Deleting WithSunroof
Deleting CarDecorator
Deleting WithAirConditioning
Deleting CarDecorator
Deleting BasicCar

2.装饰器基类可以不继承组件基类吗

在装饰器模式中,CarDecorator 必须实现 Car 接口(或继承 Car 基类),否则无法保证装饰器与被装饰对象的行为一致性。这是一种模式的核心要求:装饰器与被装饰对象应该共享相同的接口

具体原因如下:

  1. 实现统一的接口
    通过实现 Car 接口,装饰器可以被视为一种特殊类型的 Car,从而在程序中保持一致的处理方式。客户端代码不需要知道具体是 Car 还是装饰器,依然可以调用 getDescription()cost() 等方法。

  2. 支持递归包装
    如果装饰器不实现 Car 接口,无法递归地嵌套装饰器。每个装饰器必须具有相同的接口,才能被进一步装饰。

如果不继承的话,就不支持装饰器嵌套递归。

#include <iostream>
#include <string>

class Car {
public:
    virtual ~Car() = default;
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

class BasicCar : public Car {
public:
    std::string getDescription() const override {
        return "Basic Car";
    }

    double cost() const override {
        return 20000.0;
    }
};

// Decorator没有继承Car
class WithAirConditioning {
private:
    Car* car;
public:
    WithAirConditioning(Car* c) : car(c) {}

    std::string getDescription() const {
        return car->getDescription() + " with Air Conditioning";
    }

    double cost() const {
        return car->cost() + 1500.0;
    }
};

int main() {
    Car* myCar = new BasicCar();
    std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;

    WithAirConditioning acDecorator(myCar);
    std::cout << acDecorator.getDescription() << " costs $" << acDecorator.cost() << std::endl;

    // 想进一步装饰为“加装天窗”的车,但WithAirConditioning无法作为Car传入:
    // WithSunroof sunroofDecorator(&acDecorator); // 错误,因为acDecorator不是Car类型

    delete myCar;
    return 0;
}

上述代码有两个问题:

  1. 无法递归嵌套装饰器WithAirConditioning 不是 Car 类型,不能进一步用其他装饰器包装。
  2. 客户端代码复杂:需要额外处理 WithAirConditioning 的接口,且不能直接将它作为一个通用的 Car 来操作。

3.对象都是如何释放的?

CarDecorator中删除了被包装的对象car。

因此,当我们删除最外层装饰器(WithSunroof)时:

  1. WithSunroof 的析构函数会调用其基类 CarDecorator 的析构函数。
  2. CarDecorator 的析构函数会 delete 它所包装的 WithAirConditioning 对象。
  3. 类似地,WithAirConditioning 的析构函数会继续调用 CarDecorator 的析构函数,最终删除 BasicCar 对象。

这种递归删除确保了所有层级的对象都被正确释放。

4.使用智能指针的版本

// 没太看懂这个版本的。

#include <iostream>
#include <memory>
#include <string>

class Car {
public:
    virtual ~Car() = default;
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

class BasicCar : public Car {
public:
    std::string getDescription() const override {
        return "Basic Car";
    }
    double cost() const override {
        return 20000.0;
    }
};

class CarDecorator : public Car {
protected:
    std::unique_ptr<Car> car;
public:
    CarDecorator(std::unique_ptr<Car> c) : car(std::move(c)) {}
    virtual ~CarDecorator() = default;
};

class WithAirConditioning : public CarDecorator {
public:
    WithAirConditioning(std::unique_ptr<Car> c) : CarDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return car->getDescription() + " with Air Conditioning";
    }
    double cost() const override {
        return car->cost() + 1500.0;
    }
};

class WithSunroof : public CarDecorator {
public:
    WithSunroof(std::unique_ptr<Car> c) : CarDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return car->getDescription() + " with Sunroof";
    }
    double cost() const override {
        return car->cost() + 1200.0;
    }
};

int main() {
    std::unique_ptr<Car> myCar = std::make_unique<BasicCar>();
    myCar = std::make_unique<WithAirConditioning>(std::move(myCar));
    myCar = std::make_unique<WithSunroof>(std::move(myCar));

    std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;
    return 0;
}

上一篇:基于麒麟服务器操作系统V10版本,部署Nginx服务、MySql服务搭建PHP环境,实现静态网站平台的搭建。


下一篇:20241116下载中科创达的TurboX D660核心板的Android11的SDK的详细LOG