桥接模式(Bridge),是结构性模式的一种,将抽象部分与它的实现部分分离,使它们都可以独立地变化。
场景描述
目前有 Windows、Linux 两种种操作系统,在操作系统上运行不同图片格式图片处理程序,有 PNG、JPG 等格式,同时还会有文本编辑软件,可以按照操作系统和应用软件两种角度构建类继承关系图,此时如果需要添加了 Mac 操作系统,或者 Office 办公软件,会导致类数量出现爆炸式增长,桥接模式将抽象部分(一般指业务实现,本例中的应用软件)和实现部分(一般指具体平台实现,本例中的操作系统)分开,利用聚合关系,从而避免了子类数量的爆炸式增长。
设计模式思想
对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用[1]。
在面向对象设计中,有一个很重要的设计原则,那就是合成/聚合复用原则。即优先使用对象合成/聚合(CARP),尽量使用合成/聚合,尽量不要使用类继承。优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。
合成(Composition,也有翻译成组合)和聚合(Aggregation)都是关联的特殊种类。聚合表示一种弱的‘拥有’关系,体现的是 A 对象可以包含 B 对象,但 B 对象不是 A 对象的一部分;合成则是一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。
源码实现
// 操作系统抽象
class ImageOS {
public:
virtual void draw(const char* data) = 0;
virtual ~ImageOS() {};
};
class ImageOSWin : public ImageOS {
public:
virtual void draw(const char* data) {
std::cout << "Windows System draw image data" << std::endl;
}
};
class ImageOSLinux : public ImageOS {
public:
virtual void draw(const char* data) {
std::cout << "Linux System draw image data" << std::endl;
}
};
class ImageOSMac : public ImageOS {
public:
virtual void draw(const char* data) {
std::cout << "Mac System draw image data" << std::endl;
}
};
// 图像格式抽象
class ImageFormat {
public:
ImageFormat(ImageOS* imageOS) : imageos_(imageOS) {};
virtual void parseFile(const char* fileName) = 0;
virtual ~ImageFormat() {};
protected:
ImageOS* imageos_;
};
class ImageJPG : public ImageFormat {
public:
ImageJPG(ImageOS* imageOS) : ImageFormat(imageOS) {};
virtual void parseFile(const char* fileName) {
std::cout << "Parse JPG file" << fileName << std::endl;
// 模拟数据
char* imageData = new char[128];
imageos_->draw(imageData);
delete imageData;
}
};
class ImagePNG : public ImageFormat {
public:
ImagePNG(ImageOS* imageOS) : ImageFormat(imageOS) {};
virtual void parseFile(const char* fileName) {
std::cout << "Parse PNG file" << fileName << std::endl;
// 模拟数据
char* imageData = new char[128];
imageos_->draw(imageData);
delete imageData;
}
};
复制代码
源码实现
参考资料
评论