设计模式之委托模式
委托设计模式(Delegate Pattern)是一种行为设计模式,它允许一个对象将某些责任委托给另一个对象。在委托模式中,有两个主要角色:委托者(Delegator)和被委托者(Delegate)。委托者将任务委托给被委托者,而被委托者负责执行这些任务。
主要角色:
- 委托者(Delegator):
- 接受客户端的请求。
- 将请求委托给被委托者。
- 可以有自己的行为,也可以仅仅是将请求转发。
- 被委托者(Delegate):
- 负责执行具体的任务。
- 可以是接口或者抽象类,使得委托者可以委托不同的实现。
优点:
- 解耦:委托者和被委托者之间的解耦,使得它们可以独立变化。
- 扩展性:可以很容易地添加新的被委托者,从而扩展功能。
- 灵活性:委托者可以根据需要动态地改变被委托者。
缺点:
- 复杂性:可能会增加系统的复杂性,因为需要维护委托关系。
- 性能开销:委托可能会引入一些额外的性能开销。
实现步骤:
- 定义被委托者接口或抽象类。
- 实现具体的被委托者类。
- 定义委托者类,并在其中包含一个被委托者的引用或指针。
- 委托者将任务转发给被委托者。
示例:
下面是一个简单的委托模式实现示例:
#include <iostream>
#include <string>
// 被委托者接口
class Printer {
public:
virtual void print(std::string message) = 0;
virtual ~Printer() {}
};
// 具体的被委托者实现
class ConsolePrinter : public Printer {
public:
void print(std::string message) override {
std::cout << "ConsolePrinter: " << message << std::endl;
}
};
// 另一个被委托者实现
class FilePrinter : public Printer {
public:
void print(std::string message) override {
std::cout << "FilePrinter: " << message << " (saved to file)" << std::endl;
}
};
// 委托者
class PrintManager {
private:
Printer* printer; // 持有被委托者的引用
public:
PrintManager(Printer* p) : printer(p) {}
void setPrinter(Printer* p) {
printer = p;
}
void print(std::string message) {
if (printer != nullptr) {
printer->print(message); // 委托给被委托者
}
}
};
int main() {
ConsolePrinter consolePrinter;
FilePrinter filePrinter;
PrintManager manager(&consolePrinter);
manager.print("Hello World!");
// 更改被委托者
manager.setPrinter(&filePrinter);
manager.print("Hello File!");
return 0;
}
在这个例子中,PrintManager
是委托者,它将打印任务委托给 ConsolePrinter
或 FilePrinter
。通过这种方式,PrintManager
可以在不改变自身代码的情况下,灵活地改变打印行为。
注意,这里用到了多态。在提供的代码示例中,Printer* printer;
这一行声明了一个指向 Printer
类型的指针,这是一个抽象基类。多态在这里体现在以下几个方面:
- 基类指针指向派生类对象:
Printer* printer;
可以指向任何继承自Printer
的派生类对象,如ConsolePrinter
或FilePrinter
。
- 虚函数:
Printer
类中定义了一个虚函数void print(std::string message);
,这意味着在派生类中可以对这个函数进行重写(override)。
- 动态绑定:
- 当通过基类指针调用
print
方法时,会根据对象的实际类型来调用相应的派生类中的重写函数。这是运行时多态的体现。
在main
函数中,以下代码展示了多态的使用:
- 当通过基类指针调用
ConsolePrinter consolePrinter;
FilePrinter filePrinter;
PrintManager manager(&consolePrinter);
manager.print("Hello World!");
// 更改被委托者
manager.setPrinter(&filePrinter);
manager.print("Hello File!");
在这里,PrintManager
的 print
方法通过基类指针 printer
调用 print
函数。由于 printer
指向的是 ConsolePrinter
对象,第一次调用 print
时,会调用 ConsolePrinter
的 print
方法。当 printer
被设置为指向 FilePrinter
对象时,再次调用 print
方法,则会调用 FilePrinter
的 print
方法。这就是多态的动态绑定行为。