来自chatgpt
1.介绍
装饰器设计模式(Decorator Pattern)是一种结构型设计模式,允许你通过将对象包装 在一个装饰器类中来动态地为对象添加新的功能。装饰器模式通常用于当需要扩展一个类的功能时,而不需要修改该类的源代码。它通过创建一个装饰器类 来实现这一目标,并且可以将多个装饰器链式组合。
装饰器模式的关键组成部分:
- Component(组件): 一个接口或抽象类,定义了被装饰对象的标准行为。
- ConcreteComponent(具体组件): 实现了Component接口的具体类,表示被装饰的对象。
- Decorator (装饰器): 一个实现了Component接口的抽象类,它持有一个Component对象并委托所有行为给它。
- ConcreteDecorator(具体装饰器): 装饰器类的具体实现,它在调用委托的行为之前或之后执行额外的功能。
例子:
cpp
#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
基类),否则无法保证装饰器与被装饰对象的行为一致性。这是一种模式的核心要求:装饰器与被装饰对象应该共享相同的接口。
具体原因如下:
-
实现统一的接口
通过实现
Car
接口,装饰器可以被视为一种特殊类型的Car
,从而在程序中保持一致的处理方式。客户端代码不需要知道具体是Car
还是装饰器,依然可以调用getDescription()
和cost()
等方法。 -
支持递归包装
如果装饰器不实现
Car
接口,无法递归地嵌套装饰器。每个装饰器必须具有相同的接口,才能被进一步装饰。
如果不继承的话,就不支持装饰器嵌套递归。
cpp
#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;
}
上述代码有两个问题:
- 无法递归嵌套装饰器 :
WithAirConditioning
不是Car
类型,不能进一步用其他装饰器包装。 - 客户端代码复杂 :需要额外处理
WithAirConditioning
的接口,且不能直接将它作为一个通用的Car
来操作。
3.对象都是如何释放的?
CarDecorator中删除了被包装的对象car。
因此,当我们删除最外层装饰器(WithSunroof
)时:
WithSunroof
的析构函数会调用其基类CarDecorator
的析构函数。CarDecorator
的析构函数会delete
它所包装的WithAirConditioning
对象。- 类似地,
WithAirConditioning
的析构函数会继续调用CarDecorator
的析构函数,最终删除BasicCar
对象。
这种递归删除确保了所有层级的对象都被正确释放。
4.使用智能指针的版本
// 没太看懂这个版本的。
cpp
#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;
}