Decorator
装饰
动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。
解决什么问题
在某些情况下我们可能会”过度地使用继承来扩展对象的功能“,由于继承为类型引入的静态特质(继承自基类的东西无法改变,被绑死在这个基类上),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
如何使”对象功能的扩展“能够根据需要来动态地实现?同时避免”扩展功能的增多“带来的子类膨胀问题?从而使得任何”功能扩展变化“所导致的影响降为最低。
结构
要点总结
- 通过采用组合而非继承的手法,Decorator模式实现了在运动时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的”灵活性差“和”多子类衍生问题“。
- Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
- Decorator模式的目的并非解决”多子类衍生的多继承“问题,Decorator模式应用的要点在于解决”主体类在多个方向上的扩展功能“--是为”装饰“的含义。
注意:当某个类继承自另一个类,且拥有该类指针,则很有可能采用的是Decorator设计模式
示例:流操作
// 多子类继承
// 业务操作
class Stream {
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream() {}
};
// 主体类
class FileStream : public Stream {
public:
virtual char Read(int number) {
// 文件流读
}
virtual void Seek(int position) {
// 文件流定位
}
virtual void Write(char data) {
// 文件流写
}
};
class NetworkStream : public Stream {
public:
virtual char Read(int number) {
// 网络流读
}
virtual void Seek(int position) {
// 网络流定位
}
virtual void Write(char data) {
// 网络流写
}
};
class MemoryStream : public Stream {
public:
virtual char Read(int number) {
// 内存流读
}
virtual void Seek(int position) {
// 内存流定位
}
virtual void Write(char data) {
// 内存流写
}
};
// 扩展操作
// 加密功能
class CryptoFileStream : public FileStream {
public:
virtual char Read(int number) {
// 额外的加密操作
FileStream::Read(number); // 读文件流
// ...
}
virtual void Seek(int position) {
// 额外的加密操作
FileStream::Seek(position); // 读文件流
// ...
}
virtual void Write(char data) {
// 额外的加密操作
FileStream::Write(data); // 读文件流
// ...
}
};
class CryptoNetworkStream : public NetworkStream {
public:
virtual char Read(int number) {
// 额外的加密操作
NetworkStream::Read(number); // 读文件流
// ...
}
virtual void Seek(int position) {
// 额外的加密操作
NetworkStream::Seek(position); // 读文件流
// ...
}
virtual void Write(char data) {
// 额外的加密操作
NetworkStream::Write(data); // 读文件流
// ...
}
};
class CryptoMemoryStream : public MemoryStream {
// ...
};
// 缓冲功能
class BufferedFileStream : public FileStream {
// ...
};
class BufferedNetworkStream : public NetworkStream {
// ...
};
class BufferedMemoryStream : public MemoryStream {
// ...
};
// 缓冲+加密
class CryptoBufferedFileStream : public FileStream {
public:
virtual char Read(int number) {
// 加密操作
// 缓冲操作
FileStream::Read(number);
}
// ...
};
// ...
void Process() {
// 编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 = new CryptoBufferedFileStream();
}
类图关系
// 修改后
// 业务操作
class Stream {
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream() {}
};
// 主体类
class FileStream : public Stream {
public:
virtual char Read(int number) {
// 文件流读
}
virtual void Seek(int position) {
// 文件流定位
}
virtual void Write(char data) {
// 文件流写
}
};
class NetworkStream : public Stream {
public:
virtual char Read(int number) {
// 网络流读
}
virtual void Seek(int position) {
// 网络流定位
}
virtual void Write(char data) {
// 网络流写
}
};
class MemoryStream : public Stream {
public:
virtual char Read(int number) {
// 内存流读
}
virtual void Seek(int position) {
// 内存流定位
}
virtual void Write(char data) {
// 内存流写
}
};
// 扩展操作
// 加密功能
class CryptoStream : public Stream {
Stream* stream; // 将由继承而被固定的 改为运行时动态的绑定
public:
CryptoStream(Stream* stm) : stream(stm) { }
virtual char Read(int number) {
// 额外的加密操作
stream->Read(number); // 读文件流
// ...
}
virtual void Seek(int position) {
// 额外的加密操作
stream->Seek(position); // 读文件流
// ...
}
virtual void Write(char data) {
// 额外的加密操作
stream->Write(data); // 读文件流
// ...
}
};
// 缓冲功能
class BufferedStream : public Stream {
// ...
};
void Process() {
// 运行时装配
FileStream *s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedStream *s3 = new BufferedStream(s1);
BufferedStream* s4 = new BufferedStream(s2);
}
// Decorator
// 业务操作
class Stream {
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream() {}
};
// 主体类
class FileStream : public Stream {
public:
virtual char Read(int number) {
// 文件流读
}
virtual void Seek(int position) {
// 文件流定位
}
virtual void Write(char data) {
// 文件流写
}
};
class NetworkStream : public Stream {
public:
virtual char Read(int number) {
// 网络流读
}
virtual void Seek(int position) {
// 网络流定位
}
virtual void Write(char data) {
// 网络流写
}
};
class MemoryStream : public Stream {
public:
virtual char Read(int number) {
// 内存流读
}
virtual void Seek(int position) {
// 内存流定位
}
virtual void Write(char data) {
// 内存流写
}
};
// 扩展操作
class DecoratorStream : public Stream {
protected:
Stream* stream;
DecoratorStream(Stream* stm) : stream(stm) {
}
};
// 加密功能
class CryptoStream : public DecoratorStream {
public:
CryptoStream(Stream* stm) : DecoratorStream(stm) { }
virtual char Read(int number) {
// 额外的加密操作
stream->Read(number); // 读文件流
// ...
}
virtual void Seek(int position) {
// 额外的加密操作
stream->Seek(position); // 读文件流
// ...
}
virtual void Write(char data) {
// 额外的加密操作
stream->Write(data); // 读文件流
// ...
}
};
// 缓冲功能
class BufferedStream : public DecoratorStream {
// ...
};
void Process() {
// 运行时装配
FileStream *s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedStream *s3 = new BufferedStream(s1);
BufferedStream* s4 = new BufferedStream(s2);
}
此时的类图关系
Bridge
桥
将抽象部分(业务功能)与实现部分(平台实现)分离,使得它们都可以独立地变化。
解决什么问题
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个变化的维度。
如何应对这种”多维度的变化“?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?
结构
要点总结
- Bridge模式使用”对象间的组合关系“解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自的维度的变化,即”子类化“它们。
- Bridge模式有时候勒斯与多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决办法。
- Bridge模式的应用一般在”两个非常强的变化维度“,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
示例:Message轻量版和完美版,且对应不同平台
// 最初实现版本
class Messager {
public:
virtual ~Messager() {}
virtual void Login(const std::string& username, const std::string& password) = 0;
virtual void SendMessage(const std::string& message) = 0;
virtual void SendPicture(const Image& picture) = 0;
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
};
// 平台实现
class PCMessagerBase : public Message {
public:
virtual void PlaySound() {
// ...
}
virtual void DrawShape() {
// ...
}
virtual void WriteText() {
// ...
}
virtual void Connect() {
// ...
}
}
class MobileMessagerBase : public Message {
public:
virtual void PlaySound() {
// ...
}
virtual void DrawShape() {
// ...
}
virtual void WriteText() {
// ...
}
virtual void Connect() {
// ...
}
}
// 业务抽象
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(const std::string& username, const std::string& password) {
PCMessagerBase::Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
PCMessagerBase::WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
PCMessagerBase::DrawShape();
// ...
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(const std::string& username, const std::string& password) {
PCMessagerBase::PlaySound();
// ...
PCMessagerBase::Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
PCMessagerBase::PlaySound();
// ...
PCMessagerBase::WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
PCMessagerBase::PlaySound();
// ...
PCMessagerBase::DrawShape();
// ...
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(const std::string& username, const std::string& password) {
MobileMessagerBase::Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
MobileMessagerBase::WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
MobileMessagerBase::DrawShape();
// ...
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(const std::string& username, const std::string& password) {
MobileMessagerBase::PlaySound();
// ...
MobileMessagerBase::Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
MobileMessagerBase::PlaySound();
// ...
MobileMessagerBase::WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
MobileMessagerBase::PlaySound();
// ...
MobileMessagerBase::DrawShape();
// ...
}
};
// ...
void Process() {
// 编译时装配
Message* m = new MobileMessagerPerfect();
}
// Bridge
class Messager {
protected:
MessagerImp* messagerImp;
public:
Messager(MessagerImp* imp) : messagerImp(imp) {
}
virtual ~Messager() {}
virtual void Login(const std::string& username, const std::string& password) = 0;
virtual void SendMessage(const std::string& message) = 0;
virtual void SendPicture(const Image& picture) = 0;
};
class MessagerImp {
public:
virtual ~MessagerImp() {}
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
};
// 平台实现
class PCMessagerImp : public MessagerImp {
public:
virtual void PlaySound() {
// ...
}
virtual void DrawShape() {
// ...
}
virtual void WriteText() {
// ...
}
virtual void Connect() {
// ...
}
}
class MobileMessagerImp : public MessagerImp {
public:
virtual void PlaySound() {
// ...
}
virtual void DrawShape() {
// ...
}
virtual void WriteText() {
// ...
}
virtual void Connect() {
// ...
}
}
// 业务抽象
class MessagerLite : public Messager {
public:
MessagerLite(MessagerImp* imp) : Messager(imp) {
}
virtual void Login(const std::string& username, const std::string& password) {
messagerImp->Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
messagerImp->WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
messagerImp->DrawShape();
// ...
}
};
class MessagerPerfect : public Messager {
public:
MessagerPerfect(MessagerImp* imp) : Messager(imp) {
}
virtual void Login(const std::string& username, const std::string& password) {
messagerImp->PlaySound();
// ...
messagerImp->Connect();
// ...
}
virtual void SendMessage(const std::string& message) {
messagerImp->PlaySound();
// ...
messagerImp->WriteText();
// ...
}
virtual void SendPicture(const Image& picture) {
messagerImp->PlaySound();
// ...
messagerImp->DrawShape();
// ...
}
};
// ...
void Process() {
// 运行时装配
MessagerImp* mImp = new PCMessagerImp();
Message* m = new MessagerPerfect(mImp);
}