概念:一种行为设计模式,它定义了一系列算法,并将每个算法封装起来(把这些算法理解成策略),使它们可以互相替换。通过使用策略模式,可以在运行时选择算法的行为。
应用场景:1.多算法替换:当一个系统需要根据不同的情况选择不同的算法或策略时,可以使用策略模式。例如,对于排序算法,可以根据数据量大小选择使用快速排序、归并排序或插入排序等不同的排序策略。
2.避免条件语句:当代码中存在大量的条件语句,根据不同条件执行不同的操作时,可以考虑使用策略模式来消除这些条件语句。通过将每个条件分支封装成一个独立的策略类,可以简化代码逻辑并提高代码的可维护性和可扩展性。
3.算法的扩展和维护:当系统中的算法经常变化或需要新增算法时,使用策略模式可以方便地扩展和维护代码。只需要添加新的策略类,并将其注册到策略上下文中,而无需修改现有的代码。
总结:策略模式适用于需要在运行时选择不同算法或策略的场景,以及需要将算法的实现与调用代码解耦的情况
实现思路:1.定义一个策略接口(Strategy),其中包含定义策略方法的纯虚函数或抽象方法。
2.创建具体的策略类,它们实现了策略接口,并提供具体的算法实现。
3.定义一个上下文类(Context),它包含一个策略对象的成员变量,并提供设置策略和执行策略的方法。
在上下文类中,根据具体的业务逻辑或条件,选择合适的策略,并在执行方法中调用策略对象的方法。
在客户端代码中,创建上下文对象并设置初始策略。根据需要,可以在运行时动态地切换和应用不同的策略。
代码实例:
1.商品销售定价
#include
#include
// 抽象策略类
class DiscountStrategy {
public:
virtual double applyDiscount(double price) const = 0;
};
// 具体策略类1:固定折扣
class FixedDiscountStrategy : public DiscountStrategy {
public:
double applyDiscount(double price) const override {
return price * 0.8; // 固定折扣为80%
}
};
// 具体策略类2:满减
class ThresholdDiscountStrategy : public DiscountStrategy {
public:
double applyDiscount(double price) const override {
if (price >= 100) {
return price - 20; // 满100减20
} else {
return price;
}
}
};
// 上下文类
class PromotionContext {
private:
DiscountStrategy* strategy;
public:
PromotionContext(DiscountStrategy* strategy) : strategy(strategy) {}
double calculateDiscountedPrice(double price) const {
return strategy->applyDiscount(price);
}
};
int main() {
// 创建具体策略对象
DiscountStrategy* strategy1 = new FixedDiscountStrategy();
DiscountStrategy* strategy2 = new ThresholdDiscountStrategy();
// 创建上下文对象,并指定具体策略
PromotionContext context1(strategy1);
PromotionContext context2(strategy2);
double price = 120; // 商品原价
// 计算折扣后的价格
double discountedPrice1 = context1.calculateDiscountedPrice(price);
double discountedPrice2 = context2.calculateDiscountedPrice(price);
std::cout << "原价: " << price << std::endl;
std::cout << "固定折扣后的价格: " << discountedPrice1 << std::endl;
std::cout << "满减后的价格: " << discountedPrice2 << std::endl;
// 释放资源
delete strategy1;
delete strategy2;
return 0;
}
2.排序算法选择
#include
#include
#include
// 策略接口
class SortingStrategy {
public:
virtual void sort(std::vector& data) = 0;
};
// 归并排序策略
class MergeSortStrategy : public SortingStrategy {
public:
void sort(std::vector& data) override {
std::cout << "Using Merge Sort." << std::endl;
// 归并排序逻辑...
std::sort(data.begin(), data.end());
}
};
// 快速排序策略
class QuickSortStrategy : public SortingStrategy {
public:
void sort(std::vector& data) override {
std::cout << "Using Quick Sort." << std::endl;
// 快速排序逻辑...
std::sort(data.begin(), data.end());
}
};
// 策略上下文
class SortingContext {
private:
SortingStrategy* strategy; // 策略对象
public:
SortingContext(SortingStrategy* strategy) : strategy(strategy) {}
void setStrategy(SortingStrategy* newStrategy) {
strategy = newStrategy;
}
void sortData(std::vector& data) {
strategy->sort(data);
}
};
int main() {
std::vector data = { 8, 2, 5, 1, 9, 3, 6, 4, 7 };
SortingContext context(new MergeSortStrategy()); // 使用归并排序策略
context.sortData(data);
// 根据数据量选择策略
if (data.size() > 1000) {
context.setStrategy(new QuickSortStrategy()); // 使用快速排序策略
} else {
context.setStrategy(new MergeSortStrategy()); // 使用归并排序策略
}
context.sortData(data);
return 0;
}
概念:是一种行为设计模式,它允许你将请求沿着处理者链进行传递。
实现思路:1.定义处理者接口,接口里面有代表下一个处理者的属性,还有请求处理的虚函数和设置下一个处理者的set方法。
2.创建具体的处理者类,实现处理请求虚函数。
3.构建责任链,创建处理者对象的链式结构,确定它们的顺序。
4.发送请求,将请求发送给责任链的第一个处理者。
代码实例:
#include
#include
// 请求类
class PurchaseRequest {
private:
std::string productName;
double amount;
public:
PurchaseRequest(const std::string& productName, double amount)
: productName(productName), amount(amount) {}
std::string getProductName() const {
return productName;
}
double getAmount() const {
return amount;
}
};
// 抽象处理者类
class Approver {
protected:
Approver* nextApprover;
public:
Approver() : nextApprover(nullptr) {}
void setNextApprover(Approver* approver) {
nextApprover = approver;
}
virtual void processRequest(const PurchaseRequest& request) = 0;
};
// 具体处理者类
class Manager : public Approver {
public:
void processRequest(const PurchaseRequest& request) {
if (request.getAmount() <= 1000.0) {
std::cout << "Manager approves the purchase of " << request.getProductName() << std::endl;
} else if (nextApprover != nullptr) {
nextApprover->processRequest(request);
} else {
std::cout << "Purchase request cannot be approved." << std::endl;
}
}
};
class Director : public Approver {
public:
void processRequest(const PurchaseRequest& request) {
if (request.getAmount() <= 5000.0) {
std::cout << "Director approves the purchase of " << request.getProductName() << std::endl;
} else if (nextApprover != nullptr) {
nextApprover->processRequest(request);
} else {
std::cout << "Purchase request cannot be approved." << std::endl;
}
}
};
class VicePresident : public Approver {
public:
void processRequest(const PurchaseRequest& request) {
if (request.getAmount() <= 10000.0) {
std::cout << "Vice President approves the purchase of " << request.getProductName() << std::endl;
} else if (nextApprover != nullptr) {
nextApprover->processRequest(request);
} else {
std::cout << "Purchase request cannot be approved." << std::endl;
}
}
};
// 客户端代码
int main() {
// 创建处理者对象
Approver* manager = new Manager();
Approver* director = new Director();
Approver* vicePresident = new VicePresident();
// 设置责任链的顺序
manager->setNextApprover(director);
director->setNextApprover(vicePresident);
// 创建购买请求
PurchaseRequest request1("Product A", 500.0);
PurchaseRequest request2("Product B", 3000.0);
PurchaseRequest request3("Product C", 12000.0);
// 处理购买请求
manager->processRequest(request1);
manager->processRequest(request2);
manager->processRequest(request3);
// 释放内存
delete manager;
delete director;
delete vicePresident;
return 0;
}
常见使用场景:1.日志记录:根据日志级别将日志消息传递给不同的处理者进行处理。2.身份验证和授权 3.审批流程 4.异常处理
概念:工厂方法模式是一种创建型设计模式, 该模式定义了一个创建对象的接口,但具体的对象创建由子类决定。这种模式使得对象的创建延迟到子类,从而实现了对扩展开放、对修改关闭的原则。
实现思路:1.定义产品接口,首先需要定义一个产品接口,该接口定义了产品对象的通用方法,具体的产品类将实现这个接口。
2.创建具体产品类(Concrete Product Classes):针对每种产品创建具体的产品类,实现产品接口,并提供具体的实现逻辑。
3.创建工厂接口(Factory Interface):定义一个工厂接口,该接口声明了一个用于创建产品对象的方法。
4.创建具体工厂类(Concrete Factory Classes):对于每种产品,创建一个具体的工厂类,实现工厂接口,并在工厂方法中实例化具体的产品对象。
5.客户端使用:在客户端中,通过调用工厂方法来获取产品对象,而无需直接实例化具体的产品类。
代码模板:
#include
// 产品接口
class Product {
public:
virtual void use() = 0;
};
// 具体产品类A
class ConcreteProductA : public Product {
public:
void use() override {
std::cout << "使用具体产品A" << std::endl;
}
};
// 具体产品类B
class ConcreteProductB : public Product {
public:
void use() override {
std::cout << "使用具体产品B" << std::endl;
}
};
// 工厂接口
class Factory {
public:
virtual Product* createProduct() = 0;
};
// 具体工厂类A
class ConcreteFactoryA : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductA();
}
};
// 具体工厂类B
class ConcreteFactoryB : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductB();
}
};
// 客户端
int main() {
Factory* factoryA = new ConcreteFactoryA();
Product* productA = factoryA->createProduct();
productA->use();
Factory* factoryB = new ConcreteFactoryB();
Product* productB = factoryB->createProduct();
productB->use();
delete factoryA;
delete productA;
delete factoryB;
delete productB;
return 0;
}
工厂方法模式的优点:1.客户端通过调用工厂方法来创建对象,可以针对不同的产品类进行扩展,符合开放封闭原则。
2.每个具体产品对应一个具体工厂,符合单一职责原则。
工厂方法模式的缺点: 1.每增加一个具体产品,就需要增加一个对应的具体工厂类,导致类的个数增加,增加了系统的复杂度。
代码示例:
#include
#include
概念:抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象。客户端通过使用抽象工厂及其产品接口来创建对象,从而将客户端与具体的产品实现解耦。
实现思路:1.定义抽象产品接口(Abstract Product Interface):创建一组产品对象的接口,包含产品对象共同的方法。
2.定义具体产品类(Concrete Product Classes):实现抽象产品接口,提供具体产品的实现。
3.定义抽象工厂接口(Abstract Factory Interface):声明创建一组相关产品对象的方法。
4.定义具体工厂类(Concrete Factory Classes):实现抽象工厂接口,负责创建具体产品对象。
代码模板:
#include
// 抽象产品A
class AbstractProductA {
public:
virtual void use() = 0;
};
// 具体产品A1
class ConcreteProductA1 : public AbstractProductA {
public:
void use() override {
std::cout << "Using ConcreteProductA1" << std::endl;
}
};
// 具体产品A2
class ConcreteProductA2 : public AbstractProductA {
public:
void use() override {
std::cout << "Using ConcreteProductA2" << std::endl;
}
};
// 抽象产品B
class AbstractProductB {
public:
virtual void consume() = 0;
};
// 具体产品B1
class ConcreteProductB1 : public AbstractProductB {
public:
void consume() override {
std::cout << "Consuming ConcreteProductB1" << std::endl;
}
};
// 具体产品B2
class ConcreteProductB2 : public AbstractProductB {
public:
void consume() override {
std::cout << "Consuming ConcreteProductB2" << std::endl;
}
};
// 抽象工厂
class AbstractFactory {
public:
virtual AbstractProductA* createProductA() = 0;
virtual AbstractProductB* createProductB() = 0;
};
// 具体工厂1
class ConcreteFactory1 : public AbstractFactory {
public:
AbstractProductA* createProductA() override {
return new ConcreteProductA1();
}
AbstractProductB* createProductB() override {
return new ConcreteProductB1();
}
};
// 具体工厂2
class ConcreteFactory2 : public AbstractFactory {
public:
AbstractProductA* createProductA() override {
return new ConcreteProductA2();
}
AbstractProductB* createProductB() override {
return new ConcreteProductB2();
}
};
int main() {
AbstractFactory* factory1 = new ConcreteFactory1();
AbstractProductA* productA1 = factory1->createProductA();
AbstractProductB* productB1 = factory1->createProductB();
productA1->use();
productB1->consume();
delete factory1;
delete productA1;
delete productB1;
AbstractFactory* factory2 = new ConcreteFactory2();
AbstractProductA* productA2 = factory2->createProductA();
AbstractProductB* productB2 = factory2->createProductB();
productA2->use();
productB2->consume();
delete factory2;
delete productA2;
delete productB2;
return 0;
}
抽象工厂模式的优点:1.客户端通过抽象工厂接口来创建对象,可以轻松替换不同的具体工厂,实现不同产品族的切换。
2.抽象工厂保证了一系列相关产品的一致性,符合依赖倒置原则。
抽象工厂模式的缺点:1.增加新的产品族比较困难,需要修改抽象工厂的接口和所有具体工厂的实现。
代码实例:
#include
// 步骤1: 定义抽象产品接口
class ProductService {
public:
virtual void createProduct() = 0;
};
class OrderService {
public:
virtual void createOrder() = 0;
};
// 步骤2: 定义具体产品类
class ProductServiceA : public ProductService {
public:
void createProduct() override {
std::cout << "Creating product using ProductServiceA" << std::endl;
}
};
class ProductServiceB : public ProductService {
public:
void createProduct() override {
std::cout << "Creating product using ProductServiceB" << std::endl;
}
};
class OrderServiceA : public OrderService {
public:
void createOrder() override {
std::cout << "Creating order using OrderServiceA" << std::endl;
}
};
class OrderServiceB : public OrderService {
public:
void createOrder() override {
std::cout << "Creating order using OrderServiceB" << std::endl;
}
};
// 步骤3: 定义抽象工厂接口
class ServiceFactory {
public:
virtual ProductService* createProductService() = 0;
virtual OrderService* createOrderService() = 0;
};
// 步骤4: 定义具体工厂类
class ServiceAFactory : public ServiceFactory {
public:
ProductService* createProductService() override {
return new ProductServiceA();
}
OrderService* createOrderService() override {
return new OrderServiceA();
}
};
class ServiceBFactory : public ServiceFactory {
public:
ProductService* createProductService() override {
return new ProductServiceB();
}
OrderService* createOrderService() override {
return new OrderServiceB();
}
};
// 示例使用
int main() {
// 创建具体工厂对象
ServiceFactory* factoryA = new ServiceAFactory();
ServiceFactory* factoryB = new ServiceBFactory();
// 使用具体工厂对象创建产品和订单对象
ProductService* productServiceA = factoryA->createProductService();
OrderService* orderServiceA = factoryA->createOrderService();
ProductService* productServiceB = factoryB->createProductService();
OrderService* orderServiceB = factoryB->createOrderService();
// 调用产品和订单对象的创建方法
productServiceA->createProduct(); // 输出: Creating product using ProductServiceA
orderServiceA->createOrder(); // 输出: Creating order using OrderServiceA
productServiceB->createProduct(); // 输出: Creating product using ProductServiceB
orderServiceB->createOrder(); // 输出: Creating order using OrderServiceB
// 释放资源
delete productServiceA;
delete orderServiceA;
delete productServiceB;
delete orderServiceB;
delete factoryA;
delete factoryB;
return 0;
}
常见场景:第三方服务集成:当需要集成多个第三方服务,并且每个服务都有自己的一组相关对象时,抽象工厂模式可以用于创建适应不同服务的对象。
补充:1.类的静态成员变量什么时候初始化:类第一次被加载到内存中(创建类的实例,访问类的静态方法或者是访问类的静态变量)2.多线程环境下,所有线程共享code,data,heap...3.C++标准确保在main()
函数执行之前,所有的静态对象(包括全局变量和静态成员变量)都已经完成了初始化
概念:单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供全局访问点来访问该实例。它通常用于需要共享资源或需要独占访问的情况下。
饿汉式概念:在该模式中,单例实例在程序启动时就被创建,无论是否使用该实例。具体实现是将实例声明为类的静态成员,并在定义时进行初始化。
饿汉式优点:实现简单,线程安全。
饿汉式缺点:在程序启动时就创建实例,可能会造成资源浪费。
饿汉式代码模板:
class Singleton {
private:
static Singleton instance;
public:
static Singleton& getInstance() {
return instance;
}
};
Singleton Singleton::instance;
懒汉式概念: 在该模式中,单例实例在首次使用时才被创建。具体实现是将实例声明为类的静态成员。
懒汉式优点:实现简单,实例在首次使用时才被创建。
懒汉式缺点:非线程安全,多线程环境下可能会创建多个实例,所以需要使用线程安全机制。
懒汉式模板代码:
class Singleton {
private:
static Singleton* instance;
public:
static Singleton& getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return *instance;
}
};
Singleton* Singleton::instance = nullptr;
线程安全的懒汉式模板代码:双重检查锁: 在该模式中,通过加锁的方式确保只有一个线程能够创建实例。具体实现是使用双重检查来减少加锁的开销。
代码模板:
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
public:
static Singleton& getInstance() {
if (instance == nullptr) {
std::lock_guard lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
}
return *instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
实例对象定义成局部静态变量:c++11以后,局部静态变量的初始化时线程安全的,在该模式中,将实例的创建放在类的静态方法中。静态内部类只有在被访问时才会被加载,从而实现了延迟初始化。
代码模板:
class Singleton {
private:
Singleton() {}
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
};
懒汉模式和饿汉模式区别:饿汉式适用于实例创建开销较小的情况,懒汉式适用于实例创建开销较大的情况,双重检查锁适用于需要延迟初始化且对性能要求较高的情况,静态内部类适用于大多数情况下。在选择时,需要考虑线程安全性、性能、可读性等因素。
单例模式使用场景:1.系统中只需要存在一个实例对象,例如系统配置、日志记录器、线程池等。2.需要严格控制资源的访问,避免多个对象同时访问导致冲突,例如数据库连接池、文件操作等。
代码实例:
#include
#include
class Logger {
private:
static Logger* instance;
Logger() {} // 私有构造函数,禁止外部实例化
public:
static Logger* getInstance() {
if (instance == nullptr) {
instance = new Logger();
}
return instance;
}
void log(const std::string& message) {
std::cout << "Log: " << message << std::endl;
}
};
Logger* Logger::instance = nullptr;
int main() {
Logger* logger = Logger::getInstance();
logger->log("Hello, World!");
return 0;
}
概念:是一种结构型设计模式,它允许你在不修改已有对象的情况下,通过将对象包装在装饰器类中,动态地添加额外的行为和责任。装饰器模式的核心思想是使用组合而不是继承来扩展对象的功能。
设计思路:1.定义抽象组件接口:首先,需要定义一个抽象的组件接口,该接口规定了组件的基本操作或行为。这个接口可以是一个抽象类或接口,具体取决于所使用的编程语言和设计需求。
2.创建具体组件类:实现抽象组件接口的具体组件类表示被装饰的对象。它们提供了基本的功能或行为,是装饰器模式的初始状态。
3.创建装饰器基类:定义一个装饰器基类,它也实现了抽象组件接口,并持有一个指向被装饰对象的引用。这个基类可以是一个抽象类或接口,也可以是一个具体类。它为装饰器模式的核心提供了结构。
4.创建具体装饰器类:派生自装饰器基类的具体装饰器类负责在被装饰对象的基础上添加新的功能或行为。它们通过调用被装饰对象的操作,并在其前后进行额外的操作,从而实现装饰的效果。可以根据需求创建多个具体装饰器类,它们可以单独使用或按照一定顺序组合使用。
5.使用装饰器:在实际使用中,首先创建一个具体的组件对象,然后将其传递给一个或多个具体装饰器类进行装饰。装饰器类可以按照任意顺序堆叠,以实现不同的功能组合。最终,使用装饰后的对象执行操作时,将按照装饰器的层次结构依次执行额外的操作。
代码模板:
#include
#include
// 抽象组件接口
class MessageSender {
public:
virtual void send(const std::string& message) = 0;
};
// 具体组件类
class EmailSender : public MessageSender {
public:
void send(const std::string& message) override {
std::cout << "Sending email: " << message << std::endl;
}
};
// 装饰器基类
class MessageSenderDecorator : public MessageSender {
protected:
MessageSender* wrappedSender; // 持有被装饰的对象指针
public:
MessageSenderDecorator(MessageSender* sender) : wrappedSender(sender) {}
void send(const std::string& message) override {
wrappedSender->send(message);
}
};
// 具体装饰器类 - 日志记录装饰器
class Logger : public MessageSenderDecorator {
public:
Logger(MessageSender* sender) : MessageSenderDecorator(sender) {}
void send(const std::string& message) override {
std::cout << "Logging message: " << message << std::endl;
MessageSenderDecorator::send(message);
}
};
int main() {
// 创建具体组件对象
MessageSender* sender = new EmailSender();
// 应用装饰器
sender = new Logger(sender);
// 调用方法
sender->send("Hello, world!");
// 释放资源
delete sender;
return 0;
}
使用场景:
装饰器模式实现图形绘制功能:
#include
using namespace std;
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing circle" << endl;
}
};
class Square : public Shape {
public:
void draw() override {
cout << "Drawing square" << endl;
}
};
class ShapeDecorator : public Shape {
protected:
Shape* shape;
public:
ShapeDecorator(Shape* s) : shape(s) {}
void draw() override {
shape->draw();
}
};
class RedShapeDecorator : public ShapeDecorator {
public:
RedShapeDecorator(Shape* s) : ShapeDecorator(s) {}
void draw() override {
shape->draw();
cout << "Coloring shape red" << endl;
}
};
class BlueShapeDecorator : public ShapeDecorator {
public:
BlueShapeDecorator(Shape* s) : ShapeDecorator(s) {}
void draw() override {
shape->draw();
cout << "Coloring shape blue" << endl;
}
};
int main() {
Shape* circle = new Circle();
circle->draw();
Shape* square = new Square();
square->draw();
Shape* redCircle = new RedShapeDecorator(new Circle());
redCircle->draw();
Shape* blueSquare = new BlueShapeDecorator(new Square());
blueSquare->draw();
Shape* redBlueCircle = new RedShapeDecorator(new BlueShapeDecorator(new Circle()));
redBlueCircle->draw();
return 0;
}
装饰器类的补充:
在使用继承创建大量子类时,每个子类都是在原有功能的基础上进行扩展,从而形成了继承层次的深度。这样的继承层次可能会变得很复杂,而且难以管理和扩展。每次需要添加新的功能组合时,都需要创建一个新的子类。
而装饰器模式通过组合而不是继承来实现功能的扩展。每个具体装饰器类只关注一个特定的功能,它包装了一个具体组件对象,并在其上添加额外的功能。这样,你可以通过组合不同的装饰器对象,形成一个功能组合的链条。
通过装饰器模式,你可以在运行时动态地添加、删除和组合功能,而不需要修改现有代码或创建大量的子类。这将子类膨胀的问题转化为具体装饰器对象的广度问题,你可以根据需要选择不同的装饰器对象进行功能组合。
因此,装饰器模式提供了一种更灵活、可维护和可扩展的方式来处理功能的组合,避免了继承层次过深带来的问题。
概念:是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化。桥接模式通过将抽象与实现解耦,使它们可以独立进行扩展和修改,同时在它们之间建立一个桥梁,通过桥梁进行通信和协作。
设计思路:
定义抽象部分的接口(抽象类或纯虚基类):
定义实现部分的接口(抽象类或纯虚基类):
创建具体的抽象部分类(继承自抽象部分接口):
创建具体的实现部分类(继承自实现部分接口):
在客户端代码中,创建具体的抽象部分对象,并将具体的实现部分对象与之关联:
#include
// 实现部分的接口
class Engine {
public:
virtual void start() = 0;
};
// 具体的实现部分类
class GasolineEngine : public Engine {
public:
void start() override {
std::cout << "Gasoline engine started.\n";
}
};
class ElectricEngine : public Engine {
public:
void start() override {
std::cout << "Electric engine started.\n";
}
};
// 抽象部分的接口
class Car {
protected:
Engine* engine; // 持有一个实现部分的对象指针
public:
virtual void start() = 0;
};
// 具体的抽象部分类
class SedanCar : public Car {
public:
SedanCar(Engine* engine) {
this->engine = engine;
}
void start() override {
std::cout << "Sedan car is ready to go. ";
engine->start();
}
};
class SUV : public Car {
public:
SUV(Engine* engine) {
this->engine = engine;
}
void start() override {
std::cout << "SUV is ready to go. ";
engine->start();
}
};
int main() {
// 创建具体的实现部分对象
Engine* gasolineEngine = new GasolineEngine();
Engine* electricEngine = new ElectricEngine();
// 创建具体的抽象部分对象,并将实现部分对象与之关联
Car* sedanCar = new SedanCar(gasolineEngine);
Car* suv = new SUV(electricEngine);
// 调用具体的抽象部分对象的方法,实现抽象部分和实现部分的组合
sedanCar->start();
suv->start();
// 释放内存
delete gasolineEngine;
delete electricEngine;
delete sedanCar;
delete suv;
return 0;
}
适用场景:1.当存在多个维度的变化,并且每个维度都可以独立地进行扩展时,可以使用桥接模式。这样可以避免类的爆炸性增长,同时可以灵活地组合不同的维度。
2.当你需要在运行时动态地将抽象部分和实现部分组合时,可以使用桥接模式。它允许你在不修改现有代码的情况下,对抽象部分和实现部分进行灵活的组合。
概念:高层模块不应该依赖于低层模块,两者都应该依赖于抽象;抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
好处:如果不使用依赖倒置原则,可能会导致高层模块直接依赖于底层模块的具体实现,这会增加耦合度,使得代码更难以扩展和维护。
demo1:依赖倒置,只要抽象接口不变,我的高层代码就不需要改变
当使用 C++ 语言来演示依赖倒置原则时,
我们可以考虑一个简单的日志记录系统。
我们将创建一个抽象的日志接口(Logger),
然后创建两个具体的日志记录器类,
一个用于控制台输出(ConsoleLogger),
另一个用于文件输出(FileLogger)。
日志记录系统将依赖于抽象的日志接口,
而不是直接依赖于具体的实现类。
在这个例子中,Logger 是抽象的日志接口,
ConsoleLogger 和 FileLogger 分别是具体的实现类。
Application 类通过依赖注入的方式接收一个 Logger
对象,这样我们可以在运行时决定使用哪种日志记录方式,
而不需要改变 Application 类的代码。
这符合依赖倒置原则,高层模块 Application 依赖于抽象
的接口 Logger,而不是具体的实现类。这使得系统更具有灵活性和可维护性。
#include
#include
// Abstract Logger Interface
class Logger {
public:
virtual void log(const std::string& message) = 0;
};
// Console Logger Implementation
class ConsoleLogger : public Logger {
public:
void log(const std::string& message) override {
std::cout << "Console Log: " << message << std::endl;
}
};
// File Logger Implementation
class FileLogger : public Logger {
private:
std::ofstream file;
public:
FileLogger(const std::string& filename) {
file.open(filename);
}
void log(const std::string& message) override {
file << "File Log: " << message << std::endl;
}
~FileLogger() {
file.close();
}
};
// Application using Dependency Inversion
class Application {
private:
Logger* logger;
public:
Application(Logger* logger) : logger(logger) {}
void run() {
// Application logic
logger->log("Application started");
// ...
logger->log("Application finished");
}
};
int main() {
ConsoleLogger consoleLogger;
FileLogger fileLogger("log.txt");
Application appWithConsoleLogger(&consoleLogger);
appWithConsoleLogger.run();
Application appWithFileLogger(&fileLogger);
appWithFileLogger.run();
return 0;
}