桥接模式(Bridge Pattern)是一种结构型设计模式,它通过将抽象部分与实现部分分离,使得两者可以独立变化。桥接模式主要用于解决某些类的层次结构过于复杂的问题,允许将抽象和具体实现解耦,从而增强系统的灵活性和可扩展性。
特点
- 分离抽象和实现:桥接模式将抽象部分与实现部分分开,使得它们可以独立变化。
- 扩展性:可以通过增加新的实现类或者抽象类来扩展系统,而不需要修改现有代码。
- 避免多重继承:通过使用桥接模式,可以减少由于多重继承所带来的复杂性。
场景
桥接模式适用于以下场景:
- 当一个类有多个变化的维度时,使用桥接模式可以将这些维度分离开来。
- 当需要在多个抽象和实现之间进行组合时,可以使用桥接模式。
- 在需要避免类的层次结构过于复杂的情况下,桥接模式可以帮助简化设计。
举例
假设我们有一个图形绘制程序,支持不同的图形(如圆形和正方形)以及不同的颜色(如红色和蓝色)。我们可以使用桥接模式来将图形与颜色分离。
#include <iostream>
// 实现接口
class Color {
public:
virtual void applyColor() = 0; // 纯虚函数
};
// 具体实现类
class Red : public Color {
public:
void applyColor() override {
std::cout << "Applying red color." << std::endl;
}
};
class Blue : public Color {
public:
void applyColor() override {
std::cout << "Applying blue color." << std::endl;
}
};
// 抽象类
class Shape {
protected:
Color* color; // 持有一个颜色的引用
public:
Shape(Color* c) : color(c) {}
virtual void draw() = 0; // 纯虚函数
};
// 具体抽象类
class Circle : public Shape {
public:
Circle(Color* c) : Shape(c) {}
void draw() override {
std::cout << "Drawing Circle. ";
color->applyColor();
}
};
class Square : public Shape {
public:
Square(Color* c) : Shape(c) {}
void draw() override {
std::cout << "Drawing Square. ";
color->applyColor();
}
};
int main() {
Color* red = new Red();
Color* blue = new Blue();
Shape* circle = new Circle(red);
Shape* square = new Square(blue);
circle->draw(); // 输出:Drawing Circle. Applying red color.
square->draw(); // 输出:Drawing Square. Applying blue color.
// 清理内存
delete circle;
delete square;
delete red;
delete blue;
return 0;
}
装饰器模式代码举例
#include <iostream>
#include <string>
// 基础饮品接口
class Beverage {
public:
virtual std::string getDescription() = 0; // 获取描述
virtual double cost() = 0; // 获取价格
};
// 具体饮品类
class Coffee : public Beverage {
public:
std::string getDescription() override {
return "Coffee";
}
double cost() override {
return 5.0; // 咖啡的基本价格
}
};
// 装饰器基类
class CondimentDecorator : public Beverage {
protected:
Beverage* beverage; // 被装饰的饮品
public:
CondimentDecorator(Beverage* b) : beverage(b) {}
};
// 具体装饰器类
class Milk : public CondimentDecorator {
public:
Milk(Beverage* b) : CondimentDecorator(b) {}
std::string getDescription() override {
return beverage->getDescription() + ", Milk";
}
double cost() override {
return beverage->cost() + 1.5; // 加入牛奶的价格
}
};
class Sugar : public CondimentDecorator {
public:
Sugar(Beverage* b) : CondimentDecorator(b) {}
std::string getDescription() override {
return beverage->getDescription() + ", Sugar";
}
double cost() override {
return beverage->cost() + 0.5; // 加入糖的价格
}
};
int main() {
Beverage* coffee = new Coffee();
std::cout << coffee->getDescription() << " $" << coffee->cost() << std::endl;
// 添加牛奶
Beverage* milkCoffee = new Milk(coffee);
std::cout << milkCoffee->getDescription() << " $" << milkCoffee->cost() << std::endl;
// 添加糖
Beverage* milkSugarCoffee = new Sugar(milkCoffee);
std::cout << milkSugarCoffee->getDescription() << " $" << milkSugarCoffee->cost() << std::endl;
// 清理内存
delete milkSugarCoffee;
delete milkCoffee;
delete coffee;
return 0;
}
与装饰器模式的区别
装饰器模式(Decorator Pattern)也是一种结构型设计模式,它允许在运行时动态地向对象添加额外的职责。装饰器模式通常用于为对象添加新功能,而无需改变其结构。
主要区别:
-
目的不同:
- 桥接模式的主要目的是将抽象与实现分开,使它们独立变化。
- 装饰器模式的主要目的是在不改变对象的情况下,动态地为对象添加新功能。
-
结构不同:
- 在桥接模式中,抽象类和实现类都是独立的,可以通过组合关系来使用。
- 在装饰器模式中,装饰器类通常是通过继承被装饰的类来实现的,增强了对象的功能。
-
使用场景:
- 桥接模式适合于需要对多个维度进行扩展的场景。
- 装饰器模式适合于需要动态增加功能的场景。
总结
桥接模式和装饰器模式在设计思想和应用场景上有着明显的区别。桥接模式侧重于结构的解耦,使得不同的实现可以独立变化,而装饰器模式则侧重于功能的扩展,使得对象在运行时可以动态地增加新行为。