赞
踩
虽然设计模式可以提供一种优雅和可维护的解决方案,但滥用设计模式可能会导致代码变得复杂、难以理解和维护。为了避免模式滥用,请考虑以下几点:
问题需求驱动:不要为了使用设计模式而人为地引入复杂性。首先明确问题和需求,然后再考虑是否需要使用设计模式来解决问题。
简洁性:保持代码简洁和清晰是至关重要的。如果使用设计模式导致代码变得过于复杂、繁琐或难以理解,那么可能是滥用了设计模式。
适度使用:使用设计模式时要权衡利弊。不应该盲目地应用大量的设计模式,而是根据具体场景选择最合适的模式。使用适度的设计模式能够提高代码的可读性和可维护性。
理解模式原则:深入理解每个设计模式的原则、意图和适用场景非常重要。只有在你真正理解模式并且确定其适用性时,才应该使用它。不要仅仅因为某个模式听起来很酷或者流行就盲目使用。
代码复用和维护:设计模式的一个主要目标是提高代码的可重用性和可维护性。在使用设计模式之前,先考虑是否有其他简单且更直接的方式来达到相同的效果。
团队协作和沟通:如果你在一个团队中工作,与团队成员密切合作和沟通非常重要。确保每个人都理解所使用的设计模式以及其意图,以便整个团队能够更好地协同工作。
总之,设计模式应该被视为一种工具,而不是一种必须遵循的规则。正确理解设计模式的原则和意图,并根据具体情况进行适度的应用,可以避免模式滥用并获得良好的代码质量和可维护性。
当谈论到设计模式时,有几个常见的模式被广泛应用于C++编程。下面我会简要介绍几种设计模式,并提供相应的代码示例。
单例模式(Singleton Pattern)
单例模式用于确保一个类只有一个实例,并提供全局访问点。以下是一个基本的单例模式示例:
#include <iostream> // 单例类 class Singleton { private: static Singleton* instance; // 将构造函数和拷贝构造函数声明为私有,防止从外部实例化和复制对象 Singleton() {} Singleton(const Singleton&) {} public: // 静态方法获取唯一实例 static Singleton* getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } void showMessage() { std::cout << "Hello, I am a singleton object!" << std::endl; } }; // 初始化静态成员变量 Singleton* Singleton::instance = nullptr; int main() { // 获取单例实例并调用方法 Singleton* instance1 = Singleton::getInstance(); instance1->showMessage(); Singleton* instance2 = Singleton::getInstance(); instance2->showMessage(); // 检查两个实例是否相同 std::cout << "Is instance1 same as instance2? " << (instance1 == instance2 ? "Yes" : "No") << std::endl; return 0; }
使用单例模式可以确保一个类只有一个实例,并且可以全局访问该实例。这在某些情况下非常有用,例如线程池、数据库连接池等需要共享资源的场景。但请注意,在多线程环境中使用单例模式时需考虑线程安全性,可能需要使用添加锁或其他方式来保护实例的创建过程。
模板模式(Template Pattern)
是一种行为设计模式,它定义了一个算法的骨架,将具体步骤的实现延迟到子类中。模板模式使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。
结构
AbstractClass(抽象类):定义抽象方法和包含算法骨架的模板方法。模板方法通常被声明为final,以防止子类修改算法的结构。
ConcreteClassA/B(具体类A/B):实现抽象类中定义的抽象方法,完成算法的具体步骤。
示例代码
下面是一个简单的模板模式示例
#include <iostream> // 抽象类 class AbstractClass { public: void templateMethod() { // 步骤1 step1(); // 步骤2 step2(); // 步骤3 step3(); } protected: virtual void step1() = 0; virtual void step2() = 0; virtual void step3() = 0; }; // 具体类A class ConcreteClassA : public AbstractClass { protected: void step1() override { std::cout << "ConcreteClassA: Step 1" << std::endl; } void step2() override { std::cout << "ConcreteClassA: Step 2" << std::endl; } void step3() override { std::cout << "ConcreteClassA: Step 3" << std::endl; } }; // 具体类B class ConcreteClassB : public AbstractClass { protected: void step1() override { std::cout << "ConcreteClassB: Step 1" << std::endl; } void step2() override { std::cout << "ConcreteClassB: Step 2" << std::endl; } void step3() override { std::cout << "ConcreteClassB: Step 3" << std::endl; } }; int main() { // 使用具体类A AbstractClass* obj1 = new ConcreteClassA(); obj1->templateMethod(); std::cout << std::endl; // 使用具体类B AbstractClass* obj2 = new ConcreteClassB(); obj2->templateMethod(); delete obj1; delete obj2; return 0; }
在上述示例中,我们首先定义了一个抽象类AbstractClass,其中包含一个模板方法templateMethod()和三个抽象步骤step1()、step2()和step3()。
具体的步骤实现则由具体类ConcreteClassA和ConcreteClassB完成。这两个具体类继承自抽象类,并重写了抽象步骤的方法。
在main()函数中,我们创建了具体对象obj1和obj2分别代表具体类A和B的实例。然后调用它们的templateMethod()方法,触发算法的执行。可以看到,模板方法按照抽象类中定义的步骤顺序进行执行,并在每个具体类中实现了自己特定的步骤。
模板模式允许将算法的骨架放在父类中,并将具体步骤交给子类来实现。这样可以避免代码重复并提高代码的可维护性和扩展性。模板模式常用于框架或库中,其中一些算法的整体结构相同,但某些细节可能因应用而异。
代理模式(Proxy Pattern)
代理模式用于提供一个代理对象来控制对另一个对象的访问。以下是一个简单的代理模式示例:
#include <iostream> class Subject { public: virtual void request() = 0; }; class RealSubject : public Subject { public: void request() override { std::cout << "RealSubject: Handling request." << std::endl; } }; class Proxy : public Subject { private: RealSubject* realSubject; public: void request() override { if (realSubject == nullptr) { realSubject = new RealSubject(); } preRequest(); realSubject->request(); postRequest(); } void preRequest() { std::cout << "Proxy: Pre-processing request." << std::endl; } void postRequest() { std::cout << "Proxy: Post-processing request." << std::endl; } ~Proxy() { delete realSubject; } }; int main() { Proxy proxy; proxy.request(); return 0; }
在上面的示例中,Subject定义了一个抽象接口request(),RealSubject和Proxy都实现了该接口。Proxy通过持有一个RealSubject对象来代理对其的访问,在request()方法中添加了一些额外的处理逻辑。
工厂模式(Factory Pattern)
是一种创建对象的设计模式,它提供一个统一的接口来创建对象,而不需要直接暴露对象的实例化逻辑。工厂模式可以解耦对象的创建和使用,并且可以轻松扩展以支持新的产品类型。
在工厂模式中,有一个抽象的工厂类,负责定义创建产品的接口。然后,具体的工厂类继承这个抽象工厂类,并实现其方法来创建具体的产品对象。
下面是一个简单的工厂模式示例:
#include <iostream> using namespace std; // 抽象产品类 class Product { public: virtual void use() = 0; }; // 具体产品类A class ConcreteProductA : public Product { public: void use() override { cout << "Using Product A" << endl; } }; // 具体产品类B class ConcreteProductB : public Product { public: void use() override { cout << "Using Product B" << 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; }
在上面的示例中,我们定义了一个抽象的产品类Product,它有一个纯虚函数use()。然后,我们创建了两个具体的产品类ConcreteProductA和ConcreteProductB,它们分别实现了use()方法。
接下来,我们定义了一个抽象的工厂类Factory,其中有一个纯虚函数createProduct()用于创建产品对象。然后,我们创建了两个具体的工厂类ConcreteFactoryA和ConcreteFactoryB,它们分别实现了createProduct()方法。
在main()函数中,我们通过具体的工厂类来创建产品对象,并调用其use()方法。
这样,使用工厂模式可以将具体的产品对象的创建过程与客户端代码分离开来,客户端只需要通过工厂类来创建产品对象,而不需要知道具体的实现细节。这种方式可以使代码更加灵活、可扩展和易于维护。
观察者模式(Observer Pattern)
观察者模式用于建立对象之间的一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会收到通知并自动更新。以下是一个简单的观察者模式示例:
#include <iostream> #include <vector> // 抽象观察者类 class Observer { public: virtual void update() = 0; }; // 具体观察者类A class ConcreteObserverA : public Observer { public: void update() override { std::cout << "ConcreteObserverA: Received an update" << std::endl; } }; // 具体观察者类B class ConcreteObserverB : public Observer { public: void update() override { std::cout << "ConcreteObserverB: Received an update" << std::endl; } }; // 主题类 class Subject { private: std::vector<Observer*> observers; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { for (auto it = observers.begin(); it != observers.end(); ++it) { if (*it == observer) { observers.erase(it); break; } } } void notify() { for (Observer* observer : observers) { observer->update(); } } }; int main() { Subject subject; // 创建两个具体观察者对象 ConcreteObserverA observerA; ConcreteObserverB observerB; // 注册观察者对象 subject.attach(&observerA); subject.attach(&observerB); // 通知观察者对象 subject.notify(); return 0; }
在上面的示例中,我们定义了一个抽象观察者类Observer,其中有一个纯虚函数update()。然后创建了两个具体观察者类ConcreteObserverA和ConcreteObserverB,它们分别实现了update()方法。
接下来,我们定义了一个主题类Subject,其中有一个存储观察者对象的容器,并提供了一些方法来操作观察者对象。当主题发生变化时,调用notify()方法会通知所有注册的观察者对象。
在main()函数中,我们创建了一个主题对象,并注册了两个观察者对象。然后调用notify()方法通知观察者对象,它们会收到更新的通知并执行相应操作。
这样,使用观察者模式可以建立起对象之间的松耦合关系,使得系统更加灵活和可扩展。
策略模式(Strategy Pattern)
策略模式用于定义一系列算法,并使其能够互相替换。以下是一个简单的策略模式示例:
#include <iostream> // 抽象策略类 class Strategy { public: virtual void execute() = 0; }; // 具体策略类A class ConcreteStrategyA : public Strategy { public: void execute() override { std::cout << "Executing strategy A" << std::endl; } }; // 具体策略类B class ConcreteStrategyB : public Strategy { public: void execute() override { std::cout << "Executing strategy B" << std::endl; } }; // 上下文类 class Context { private: Strategy* strategy; public: Context(Strategy* strategy) : strategy(strategy) {} void setStrategy(Strategy* newStrategy) { strategy = newStrategy; } void executeStrategy() { strategy->execute(); } }; int main() { // 创建具体策略对象 ConcreteStrategyA strategyA; ConcreteStrategyB strategyB; // 创建上下文对象,并设置策略对象 Context context(&strategyA); context.executeStrategy(); // 切换策略对象 context.setStrategy(&strategyB); context.executeStrategy(); return 0; }
定义了一个抽象策略类Strategy,其中有一个纯虚函数execute()。然后创建了两个具体策略类ConcreteStrategyA和ConcreteStrategyB,它们分别实现了execute()方法。
接下来,我们定义了上下文类Context,其中有一个成员变量strategy用于保存当前的策略对象。在上下文类中,我们提供了一系列操作策略对象的方法,包括设置策略对象和执行策略。
在main()函数中,我们创建了具体策略对象,并使用上下文对象设置和切换策略对象,然后调用上下文对象的executeStrategy()方法来执行策略。这样,使用策略模式可以在运行时动态地选择不同的算法策略,而不需要修改客户端代码。这使得系统更加灵活,并且可以方便地扩展和替换不同的策略。
装饰模式(Decorator Pattern)
装饰模式用于动态地给一个对象添加额外的功能,同时又不改变其接口。以下是一个简单的装饰模式示例:
#include <iostream> // 抽象组件类 class Component { public: virtual void operation() = 0; }; // 具体组件类 class ConcreteComponent : public Component { public: void operation() override { std::cout << "Executing operation in ConcreteComponent" << std::endl; } }; // 抽象装饰类 class Decorator : public Component { protected: Component* component; public: Decorator(Component* component) : component(component) {} void operation() override { component->operation(); } }; // 具体装饰类A class ConcreteDecoratorA : public Decorator { public: ConcreteDecoratorA(Component* component) : Decorator(component) {} void operation() override { Decorator::operation(); addedBehaviour(); } void addedBehaviour() { std::cout << "Adding additional behaviour in ConcreteDecoratorA" << std::endl; } }; // 具体装饰类B class ConcreteDecoratorB : public Decorator { public: ConcreteDecoratorB(Component* component) : Decorator(component) {} void operation() override { Decorator::operation(); addedBehaviour(); } void addedBehaviour() { std::cout << "Adding additional behaviour in ConcreteDecoratorB" << std::endl; } }; int main() { // 创建具体组件对象 ConcreteComponent component; // 使用具体装饰类包装具体组件对象 ConcreteDecoratorA decoratorA(&component); ConcreteDecoratorB decoratorB(&decoratorA); // 调用装饰后的操作 decoratorB.operation(); return 0; }
在上面的示例中,我们定义了一个抽象组件类Component,其中有一个纯虚函数operation()。然后创建了一个具体组件类ConcreteComponent,它实现了operation()方法。
接下来,我们定义了一个抽象装饰类Decorator,它继承自组件类,并包含一个指向组件对象的成员变量。在抽象装饰类中,我们实现了operation()方法来调用被装饰对象的操作。
然后,我们创建了两个具体装饰类ConcreteDecoratorA和ConcreteDecoratorB,它们分别继承自抽象装饰类,并在operation()方法中增加了额外的行为。
在main()函数中,我们创建了具体组件对象,并使用具体装饰类对其进行包装。然后调用装饰后的操作,会依次执行被装饰对象和各个装饰对象的操作。这样,使用装饰模式可以在运行时动态地给一个对象添加功能,而且可以灵活地组合多个装饰器,实现对对象功能的动态扩展,同时遵循开闭原则。装饰模式可以避免使用继承导致的类爆炸问题。
值得注意的是,在装饰模式中,装饰器和被装饰对象拥有相同的接口,这使得装饰器可以透明地替代被装饰对象。这意味着客户端代码无需知道具体的装饰器或被装饰对象的存在,只需要调用共同的接口即可。
责任链模式(Chain of Responsibility Pattern)
是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求。每个处理者都可以决定是否将请求传递给下一个处理者。
结构
Handler(处理者):定义一个处理请求的接口,并持有下一个处理者的引用。
ConcreteHandlerA/B(具体处理者A/B):实现处理请求的方法,如果无法处理则将请求传递给下一个处理者。
Client(客户端):创建处理者链,并向链的第一个处理者发送请求。下面是一个简单的用于批准请假的责任链模式示例:
#include <iostream> // 抽象处理者类 class Handler { protected: Handler* next; public: Handler() : next(nullptr) {} virtual void setNext(Handler* handler) { next = handler; } virtual void handleRequest(int days) = 0; }; // 具体处理者类A class ConcreteHandlerA : public Handler { public: void handleRequest(int days) override { if (days <= 2) { std::cout << "ConcreteHandlerA: Approved the leave request" << std::endl; } else if (next != nullptr) { next->handleRequest(days); } } }; // 具体处理者类B class ConcreteHandlerB : public Handler { public: void handleRequest(int days) override { if (days <= 5) { std::cout << "ConcreteHandlerB: Approved the leave request" << std::endl; } else if (next != nullptr) { next->handleRequest(days); } } }; // 具体处理者类C class ConcreteHandlerC : public Handler { public: void handleRequest(int days) override { if (days <= 10) { std::cout << "ConcreteHandlerC: Approved the leave request" << std::endl; } else { std::cout << "ConcreteHandlerC: Leave request denied" << std::endl; } } }; int main() { // 创建具体处理者对象 ConcreteHandlerA handlerA; ConcreteHandlerB handlerB; ConcreteHandlerC handlerC; // 构建责任链 handlerA.setNext(&handlerB); handlerB.setNext(&handlerC); // 发送请假请求 handlerA.handleRequest(3); handlerA.handleRequest(7); handlerA.handleRequest(12); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。