在软件开发中,设计模式(Design Pattern)是一种被反复验证的、解决常见设计问题的通用方法。它并不是一个具体的代码实现,而是一个模板或解决方案。设计模式帮助我们以一种通用且灵活的方式设计软件架构,从而增强系统的可扩展性、可维护性和可复用性。
本文将从 创建型模式、结构型模式 和 行为型模式 三个类别详细介绍设计模式,并通过通俗易懂的示例,帮助你理解每种模式的用途和实现方式。
设计模式通常分为三大类:
下面我们将详细讲解每一类设计模式及其应用场景。
创建型模式主要处理对象的创建方式,解决如何实例化对象的问题。它使得对象的创建更加灵活,减少了与具体类的依赖。常见的创建型模式有:
单例模式是最常用的创建型设计模式,它确保某个类只有一个实例,并提供一个全局的访问点。单例模式适用于那些需要全局访问的共享资源,如配置管理、日志系统、数据库连接池等。
class Singleton {
public:
static Singleton* instance() {
if (instance_ == nullptr) {
instance_ = new Singleton();
}
return instance_;
}
private:
Singleton() {} // 构造函数私有化,防止外部创建对象
static Singleton* instance_; // 静态指针保存唯一实例
};
// 初始化静态成员变量
Singleton* Singleton::instance_ = nullptr;
int main() {
Singleton::instance()->showMessage();
return 0;
}
如果程序运行在多线程环境中,可能会遇到多个线程同时创建实例的情况。为此,我们需要在获取实例时加入互斥锁,确保只有一个线程能访问创建实例的代码块。
工厂方法模式通过定义一个接口来创建对象,但由子类决定具体实例化哪个类。它的核心思想是将对象的创建推迟到子类中,避免直接在客户端代码中实例化对象。
class Product {
public:
virtual void operation() = 0;
};
class ConcreteProductA : public Product {
public:
void operation() override {
std::cout << "Product A operation." << std::endl;
}
};
class Creator {
public:
virtual Product* createProduct() = 0;
};
class ConcreteCreatorA : public Creator {
public:
Product* createProduct() override {
return new ConcreteProductA();
}
};
抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。它适用于需要创建一组相关对象的场景,客户端通过工厂来获取一系列产品,而无需关心具体的产品类。
class AbstractProductA {
public:
virtual void operation() = 0;
};
class AbstractProductB {
public:
virtual void operation() = 0;
};
class ConcreteProductA1 : public AbstractProductA {
public:
void operation() override {
std::cout << "Product A1 operation." << std::endl;
}
};
class ConcreteProductB1 : public AbstractProductB {
public:
void operation() override {
std::cout << "Product B1 operation." << std::endl;
}
};
class AbstractFactory {
public:
virtual AbstractProductA* createProductA() = 0;
virtual AbstractProductB* createProductB() = 0;
};
class ConcreteFactory1 : public AbstractFactory {
public:
AbstractProductA* createProductA() override {
return new ConcreteProductA1();
}
AbstractProductB* createProductB() override {
return new ConcreteProductB1();
}
};
建造者模式将一个复杂对象的构建过程抽象出来,使得同样的构建过程可以创建不同的表示。建造者模式将构建过程和表示分离,让客户可以选择不同的构建方式。
class Product {
public:
void setPartA(const std::string& part) {
partA = part;
}
void setPartB(const std::string& part) {
partB = part;
}
void showProduct() {
std::cout << partA << " " << partB << std::endl;
}
private:
std::string partA;
std::string partB;
};
class Builder {
public:
virtual void buildPartA() = 0;
virtual void buildPartB() = 0;
virtual Product* getResult() = 0;
};
class ConcreteBuilder : public Builder {
public:
ConcreteBuilder() : product(new Product()) {}
void buildPartA() override {
product->setPartA("Part A");
}
void buildPartB() override {
product->setPartB("Part B");
}
Product* getResult() override {
return product;
}
private:
Product* product;
};
原型模式通过复制现有的对象来创建新的对象,而不是重新实例化一个新的对象。它适用于对象创建开销较大的场景,避免了重复创建相似对象的开销。
class Prototype {
public:
virtual Prototype* clone() = 0;
};
class ConcretePrototype : public Prototype {
public:
ConcretePrototype(int value) : value(value) {}
Prototype* clone() override {
return new ConcretePrototype(value);
}
private:
int value;
};
结构型设计模式关注如何将类和对象组织起来,帮助我们实现更清晰、更简洁的代码结构。常见的结构型模式包括:
适配器模式用于将一个类的接口转换成客户希望的另一个接口。它让原本接口不兼容的类能够一起工作。适配器模式常用于不同接口之间的兼容问题。
class Target {
public:
virtual void request() = 0;
};
class Adaptee {
public:
void specificRequest() {
std::cout << "Adaptee's specific request." << std::endl;
}
};
class Adapter : public Target {
public:
Adapter(Adaptee* adaptee) : adaptee_(adaptee) {}
void request() override {
adaptee_->specificRequest();
}
private:
Adaptee* adaptee_;
};
桥接模式将抽象与实现分离,使得它们可以独立变化。它通过组合来避免多重继承,帮助我们分离变化的维度。
class Abstraction {
public:
virtual void operation() = 0;
};
class ConcreteAbstraction : public Abstraction {
public:
ConcreteAbstraction(Implementor* implementor) : implementor_(implementor) {}
void operation() override {
implementor_->operationImpl();
}
private:
Implementor* implementor_;
};
class Implementor {
public:
virtual void operationImpl() = 0;
};
class ConcreteImplementorA : public Implementor {
public:
void operationImpl() override {
std::cout << "ConcreteImplementorA operation." << std::
endl;
}
};
组合模式允许你将多个对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式让客户端可以统一地处理单个对象和对象的组合。它主要用于需要递归地处理对象的场景,如文件系统、树形结构等。
class Component {
public:
virtual void operation() = 0;
virtual ~Component() {}
};
class Leaf : public Component {
public:
void operation() override {
std::cout << "Leaf operation." << std::endl;
}
};
class Composite : public Component {
public:
void add(Component* component) {
children.push_back(component);
}
void operation() override {
std::cout << "Composite operation." << std::endl;
for (auto child : children) {
child->operation();
}
}
private:
std::vector<Component*> children;
};
装饰器模式允许你在不改变原有对象的基础上,动态地为对象添加新的功能。它通过创建一个装饰类来包装原始对象,从而扩展其行为。装饰器模式是一种对象结构型模式,比继承更加灵活。
class Component {
public:
virtual void operation() = 0;
virtual ~Component() {}
};
class ConcreteComponent : public Component {
public:
void operation() override {
std::cout << "ConcreteComponent operation." << std::endl;
}
};
class Decorator : public Component {
public:
Decorator(Component* component) : component_(component) {}
void operation() override {
component_->operation();
addBehavior();
}
void addBehavior() {
std::cout << "Decorator added behavior." << std::endl;
}
private:
Component* component_;
};
外观模式提供一个简化的接口,屏蔽了系统中的复杂子系统,让外部客户端更容易使用。它定义了一个高层接口,访问多个子系统,减少了外部代码对复杂系统的依赖。
class SubsystemA {
public:
void operationA() {
std::cout << "SubsystemA operation." << std::endl;
}
};
class SubsystemB {
public:
void operationB() {
std::cout << "SubsystemB operation." << std::endl;
}
};
class Facade {
public:
void operation() {
subsystemA.operationA();
subsystemB.operationB();
}
private:
SubsystemA subsystemA;
SubsystemB subsystemB;
};
享元模式通过共享对象来减少内存使用,适用于大量细粒度对象的场景。享元模式将对象的状态分为内蕴状态(可以共享的部分)和外部状态(不能共享的部分),通过共享内蕴状态来节省内存。
class Flyweight {
public:
virtual void operation(int extrinsicState) = 0;
};
class ConcreteFlyweight : public Flyweight {
public:
void operation(int extrinsicState) override {
std::cout << "ConcreteFlyweight operation. State: " << extrinsicState << std::endl;
}
};
class FlyweightFactory {
public:
Flyweight* getFlyweight(int intrinsicState) {
if (flyweights.find(intrinsicState) == flyweights.end()) {
flyweights[intrinsicState] = new ConcreteFlyweight();
}
return flyweights[intrinsicState];
}
private:
std::unordered_map<int, Flyweight*> flyweights;
};
代理模式为其他对象提供代理,以控制对该对象的访问。代理模式通常用于延迟对象创建、访问控制、远程代理、虚拟代理等场景。
class Subject {
public:
virtual void request() = 0;
};
class RealSubject : public Subject {
public:
void request() override {
std::cout << "RealSubject request." << std::endl;
}
};
class Proxy : public Subject {
public:
Proxy(RealSubject* realSubject) : realSubject_(realSubject) {}
void request() override {
std::cout << "Proxy operation before real subject request." << std::endl;
realSubject_->request();
}
private:
RealSubject* realSubject_;
};
行为型设计模式专注于对象之间的通信与职责分配,优化对象之间的协作和通信流程。常见的行为型设计模式有:
责任链模式使多个对象有机会处理请求,从而避免请求的发送者和接收者耦合在一起。每个处理者对象持有下一个处理者的引用,当请求到达时,当前对象可以选择处理请求或将请求传递给下一个处理者。
class Handler {
public:
virtual void handleRequest(int request) = 0;
};
class ConcreteHandlerA : public Handler {
public:
void handleRequest(int request) override {
if (request < 10)
std::cout << "Handler A handled the request." << std::endl;
else
std::cout << "Handler A cannot handle the request." << std::endl;
}
};
命令模式将请求封装成对象,从而使我们可以用不同的请求对客户进行参数化、队列化请求、记录请求日志,或者支持撤销操作。命令模式使得请求者与执行者解耦。
class Command {
public:
virtual void execute() = 0;
};
class ConcreteCommand : public Command {
public:
void execute() override {
std::cout << "Executing command." << std::endl;
}
};
设计模式是软件开发中经过多年实践验证的解决方案,它帮助我们解决常见的设计问题,提升代码的可维护性、可扩展性和可复用性。通过设计模式,我们可以减少开发中的重复工作和错误,同时提升系统的灵活性。
在实际开发中,理解并运用设计模式可以帮助我们更加高效地解决问题,创建更加灵活且可维护的系统。