1. 装饰器模式的核心思想与应用场景
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向现有对象动态添加新功能而不改变其结构。这种模式创建了一个装饰器类,用来包装原始类,并在保持类方法签名完整性的前提下提供额外的功能。
在C++中,装饰器模式通常通过组合和继承来实现。与直接继承不同,装饰器模式提供了更灵活的扩展方式。想象一下俄罗斯套娃——每个装饰层都包裹着内层的核心对象,可以无限叠加新的功能层。
1.1 装饰器模式的四大核心组件
- Component(抽象组件):定义对象接口,可以动态添加职责
- ConcreteComponent(具体组件):实现组件接口的具体对象
- Decorator(抽象装饰器):继承自Component,并持有一个Component引用
- ConcreteDecorator(具体装饰器):向组件添加具体职责
cpp复制// 抽象组件
class Component {
public:
virtual void operation() = 0;
virtual ~Component() = default;
};
// 具体组件
class ConcreteComponent : public Component {
public:
void operation() override {
std::cout << "Basic functionality\n";
}
};
// 抽象装饰器
class Decorator : public Component {
protected:
Component* component;
public:
Decorator(Component* c) : component(c) {}
void operation() override {
if (component) component->operation();
}
};
// 具体装饰器A
class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* c) : Decorator(c) {}
void operation() override {
Decorator::operation();
addedBehavior();
}
private:
void addedBehavior() {
std::cout << "Added behavior from DecoratorA\n";
}
};
1.2 何时应该使用装饰器模式
装饰器模式特别适用于以下场景:
- 需要在不影响其他对象的情况下,动态、透明地添加职责
- 当继承扩展不切实际时(如需要大量子类的情况)
- 需要撤销或修改已添加的功能
- 系统需要运行时添加或修改对象行为
在C++标准库中,我们可以找到装饰器模式的典型应用——std::stack实际上就是std::deque的一个装饰器实现。同样,智能指针也可以被视为对原始指针的装饰。
提示:装饰器模式与代理模式在结构上相似,但目的不同。代理模式控制访问,而装饰器模式增强功能。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C++中装饰器模式的高级实现技巧
2.1 使用模板实现通用装饰器
C++模板允许我们创建更灵活的装饰器结构。通过模板化装饰器基类,我们可以装饰任意类型的组件:
cpp复制template <typename T>
class Decorator : public T {
protected:
T* component;
public:
Decorator(T* c) : component(c) {}
void operation() override {
if (component) component->operation();
}
};
// 使用示例
class MyComponent {
public:
virtual void operation() {
std::cout << "MyComponent operation\n";
}
virtual ~MyComponent() = default;
};
class MyDecorator : public Decorator<MyComponent> {
public:
MyDecorator(MyComponent* c) : Decorator<MyComponent>(c) {}
void operation() override {
Decorator<MyComponent>::operation();
std::cout << "Additional functionality\n";
}
};
这种模板化实现避免了为每个组件类型创建单独的装饰器层次结构,大大提高了代码复用性。
2.2 可变参数装饰器
C++11引入的可变参数模板可以与装饰器模式完美结合,创建可组合的装饰器链:
cpp复制template <typename T, typename... Decorators>
auto decorate(T* component, Decorators... decorators) {
// 递归展开参数包应用装饰器
return (decorators( ... (decorators(component)) ));
}
// 定义装饰器工厂函数
auto addLogging = [](auto* c) {
return new LoggingDecorator(c);
};
auto addTiming = [](auto* c) {
return new TimingDecorator(c);
};
// 使用示例
auto decorated = decorate(
new ConcreteComponent(),
addLogging,
addTiming
);
2.3 使用智能指针管理装饰器生命周期
在C++中,装饰器模式常涉及动态内存分配。使用智能指针可以避免内存泄漏:
cpp复制std::unique_ptr<Component> component =
std::make_unique<ConcreteDecoratorA>(
std::make_unique<ConcreteDecoratorB>(
std::make_unique<ConcreteComponent>()
)
);
component->operation();
这种嵌套的make_unique调用创建了一个装饰器链,当最外层的unique_ptr销毁时,整个装饰器链会被正确释放。
3. 装饰器模式在C++项目中的实际应用
3.1 增强I/O流功能
C++标准库的流对象是装饰器模式的绝佳应用场景。我们可以通过继承std::streambuf来创建自定义的流缓冲装饰器:
cpp复制class IndentStreamBuffer : public std::streambuf {
public:
IndentStreamBuffer(std::streambuf* sb, int indent = 4)
: source(sb), indentLevel(0), indentSize(indent) {}
protected:
int_type overflow(int_type c) override {
if (c == '\n') {
source->sputc(c);
for (int i = 0; i < indentLevel * indentSize; ++i) {
source->sputc(' ');
}
} else {
source->sputc(c);
}
return c;
}
private:
std::streambuf* source;
int indentLevel;
int indentSize;
};
// 使用示例
std::ostringstream oss;
oss.rdbuf(new IndentStreamBuffer(oss.rdbuf()));
3.2 实现缓存装饰器
装饰器模式非常适合实现缓存功能,特别是对于计算密集型操作:
cpp复制template <typename T>
class CachedFunction : public T {
public:
CachedFunction(T* func) : function(func) {}
auto operator()(auto... args) {
auto key = std::make_tuple(args...);
if (cache.find(key) == cache.end()) {
cache[key] = (*function)(args...);
}
return cache[key];
}
private:
T* function;
std::map<std::tuple<decltype(args)...>, decltype((*function)(args...))> cache;
};
// 使用示例
auto expensiveCalculation = [](int x) {
// 模拟耗时计算
std::this_thread::sleep_for(std::chrono::seconds(1));
return x * x;
};
auto cached = CachedFunction(expensiveCalculation);
std::cout << cached(5) << std::endl; // 计算并缓存
std::cout << cached(5) << std::endl; // 直接从缓存读取
3.3 实现权限控制装饰器
在需要动态添加权限控制的系统中,装饰器模式提供了一种优雅的解决方案:
cpp复制class User {
public:
virtual bool hasPermission(const std::string& perm) const = 0;
virtual ~User() = default;
};
class BasicUser : public User {
public:
bool hasPermission(const std::string& perm) const override {
return perm == "read";
}
};
class PermissionDecorator : public User {
protected:
User* user;
std::set<std::string> additionalPermissions;
public:
PermissionDecorator(User* u, std::set<std::string> perms)
: user(u), additionalPermissions(std::move(perms)) {}
bool hasPermission(const std::string& perm) const override {
return additionalPermissions.count(perm) ||
(user && user->hasPermission(perm));
}
};
// 使用示例
User* admin = new PermissionDecorator(
new BasicUser(),
{"write", "delete", "admin"}
);
4. 装饰器模式的高级应用与性能考量
4.1 装饰器链的动态修改
在实际应用中,我们可能需要动态添加或移除装饰器。这可以通过引入装饰器管理器来实现:
cpp复制class DecoratorManager {
public:
template <typename ComponentType>
class ManagedComponent : public ComponentType {
public:
using DecoratorFunc = std::function<ComponentType*(ComponentType*)>;
void addDecorator(DecoratorFunc decorator) {
decorators.push_back(decorator);
rebuildChain();
}
void removeDecorator(size_t index) {
if (index < decorators.size()) {
decorators.erase(decorators.begin() + index);
rebuildChain();
}
}
// 实现ComponentType的所有虚函数...
private:
std::vector<DecoratorFunc> decorators;
std::unique_ptr<ComponentType> root;
std::unique_ptr<ComponentType> current;
void rebuildChain() {
auto temp = std::make_unique<ComponentType>();
current = std::move(temp);
for (auto& decorator : decorators) {
current.reset(decorator(current.release()));
}
}
};
};
// 使用示例
using ManagedStringProcessor = DecoratorManager::ManagedComponent<StringProcessor>;
auto processor = std::make_unique<ManagedStringProcessor>();
processor->addDecorator([](auto* c) { return new TrimDecorator(c); });
processor->addDecorator([](auto* c) { return new CaseDecorator(c); });
4.2 装饰器模式的性能优化
虽然装饰器模式提供了灵活性,但多层装饰会导致一定的性能开销。以下是几种优化策略:
- 缓存装饰结果:对于纯函数装饰器,可以缓存装饰结果
- 减少装饰层数:合并可以合并的装饰逻辑
- 使用CRTP优化:通过奇异递归模板模式减少虚函数调用开销
cpp复制// 使用CRTP实现的装饰器模式
template <typename Derived, typename Component>
class CRTPDecorator : public Component {
public:
void operation() override {
static_cast<Derived*>(this)->beforeOperation();
Component::operation();
static_cast<Derived*>(this)->afterOperation();
}
};
class LoggingComponent : public CRTPDecorator<LoggingComponent, ConcreteComponent> {
public:
void beforeOperation() {
std::cout << "Operation started\n";
}
void afterOperation() {
std::cout << "Operation completed\n";
}
};
4.3 装饰器模式与C++20概念
C++20引入的概念(Concepts)可以更好地约束装饰器接口:
cpp复制template <typename T>
concept Component = requires(T t) {
{ t.operation() } -> std::same_as<void>;
};
template <Component T>
class ConceptDecorator : public T {
public:
void operation() override {
std::cout << "Decorator pre-processing\n";
T::operation();
std::cout << "Decorator post-processing\n";
}
};
这种实现方式在编译期就能检查装饰器是否满足组件接口要求,比运行时多态更安全高效。
