一些常用的软件设计模式
1 工厂模式
工厂模式(Factory Pattern):定义一个创建对象的接口,但是让子类决定要实例化的类是哪一个,将对象的创建和使用分离开来,降低代码的耦合度。
工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象而不会暴露创建逻辑。它允许在运行时确定创建哪个具体类的对象。
实现工厂模式需要创建一个工厂类,该类负责创建具体类的对象,并将它们返回给客户端。工厂类根据客户端的请求来决定创建哪个具体类的对象。这样,客户端只需要知道抽象接口和工厂类,而不需要知道具体类的实现。
#include <iostream>
using namespace std;
// 抽象产品类
class Product {
public:
virtual void operation() = 0;
};
// 具体产品类 A
class ConcreteProductA : public Product {
public:
void operation() {
cout << "ConcreteProductA operation" << endl;
}
};
// 具体产品类 B
class ConcreteProductB : public Product {
public:
void operation() {
cout << "ConcreteProductB operation" << endl;
}
};
// 工厂类
class Factory {
public:
// 创建产品的接口方法
virtual Product* createProduct() = 0;
};
// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:
Product* createProduct() {
return new ConcreteProductA();
}
};
// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:
Product* createProduct() {
return new ConcreteProductB();
}
};
int main() {
// 创建工厂 A
Factory* factoryA = new ConcreteFactoryA();
// 创建产品 A
Product* productA = factoryA->createProduct();
// 调用产品 A 的操作
productA->operation();
// 创建工厂 B
Factory* factoryB = new ConcreteFactoryB();
// 创建产品 B
Product* productB = factoryB->createProduct();
// 调用产品 B 的操作
productB->operation();
// 释放资源
delete factoryA;
delete productA;
delete factoryB;
delete productB;
return 0;
}
在上述示例中,Product
是抽象产品类,ConcreteProductA
和 ConcreteProductB
是具体产品类。Factory
是抽象工厂类,ConcreteFactoryA
和 ConcreteFactoryB
是具体工厂类。在 main()
函数中,我们创建了工厂 A 和工厂 B,并使用它们来创建产品 A 和产品 B,并调用它们的操作方法。
这里使用了虚拟析构函数,在释放资源时,通过基类指针调用虚拟析构函数,可以确保调用派生类的析构函数,从而避免内存泄漏问题。
2 单例模式
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并且提供一个全局访问点,控制对唯一实例的访问。
单例模式(Singleton Pattern)是一种常用的创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在很多场景下,单例模式都是非常有用的,比如线程池、日志系统、配置管理等。
实现单例模式需要注意的是,要保证线程安全以及防止拷贝构造函数和赋值操作符的存在,从而防止多个实例的产生。以下是一个基于C++的单例模式示例代码:
#include <iostream>
class Singleton {
private:
// 防止拷贝构造函数和赋值操作符的存在
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 私有构造函数和析构函数
Singleton() { std::cout << "Singleton instance created." << std::endl; }
~Singleton() { std::cout << "Singleton instance destroyed." << std::endl; }
public:
// 获取单例对象的静态方法
static Singleton& getInstance() {
// 静态局部变量的初始化是线程安全的
static Singleton instance;
return instance;
}
// 单例类的其他成员方法
void doSomething() {
std::cout << "Singleton instance is doing something." << std::endl;
}
};
int main() {
Singleton& s1 = Singleton::getInstance();
s1.doSomething();
// 以下语句会产生编译错误
// Singleton s2 = s1;
return 0;
}
在这个示例代码中,Singleton类的构造函数和析构函数都是私有的,这样就无法从外部创建实例或者销毁实例。而获取单例对象的方法getInstance是静态的,通过静态局部变量的方式来保证只有一个实例被创建。同时,拷贝构造函数和赋值操作符都被删除了,这样就无法通过拷贝构造函数或赋值操作符来创建新的实例。
在main函数中,我们通过Singleton::getInstance()方法获取了单例对象s1,并调用了其成员方法doSomething。由于Singleton类只有一个实例,因此每次获取到的都是同一个对象。
总结一下,单例模式是一种非常有用的设计模式,可以保证一个类只有一个实例,并提供一个全局访问点。在实现单例模式的时候需要注意线程安全、防止拷贝构造函数和赋值操作符的存在等问题。
3 观察者模式
- 观察者模式(Observer Pattern):定义了对象之间一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
观察者模式(Observer Pattern)是一种常见的设计模式,它用于在对象间建立一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
在观察者模式中,有两类角色:Subject(主题)和Observer(观察者)。Subject是被观察的对象,它维护一个Observer列表,用于记录所有依赖它的Observer。Observer是观察者,它会在Subject状态发生改变时,自动得到通知并进行更新。
下面是一个使用C++语言实现的观察者模式示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual void update(int value) = 0;
};
class Subject {
int m_value;
std::vector<Observer*> m_observers;
public:
void attach(Observer* observer) {
m_observers.push_back(observer);
}
void set_value(int value) {
m_value = value;
notify();
}
void notify() {
for(auto observer : m_observers)
observer->update(m_value);
}
};
class ConcreteObserver : public Observer {
public:
ConcreteObserver(Subject* subject) : m_subject(subject) {
m_subject->attach(this);
}
void update(int value) {
std::cout << "Received update with value: " << value << std::endl;
}
private:
Subject* m_subject;
};
int main() {
Subject subject;
ConcreteObserver observer1(&subject);
ConcreteObserver observer2(&subject);
subject.set_value(42);
return 0;
}
在上述示例代码中,Subject类代表主题,ConcreteObserver类代表具体的观察者。Subject类维护了一个Observer指针的vector,每当Subject状态发生改变时,它会遍历这个vector,调用每个Observer的update方法。ConcreteObserver在构造函数中将自己添加到Subject的观察者列表中,当Subject状态发生改变时,它的update方法就会被调用。
在主函数中,我们创建了一个Subject对象和两个ConcreteObserver对象,并将这两个观察者对象添加到Subject的观察者列表中。随后,我们调用Subject的set_value方法,这会导致Subject状态发生改变,从而触发所有观察者的更新操作。
4 装饰者模式
- 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。
装饰者模式(Decorator Pattern)是一种常用的设计模式,它用于动态地为一个对象添加额外的功能,同时又不需要修改这个对象的结构。
在装饰者模式中,有三类角色:Component(抽象构件)、ConcreteComponent(具体构件)和Decorator(装饰者)。Component是抽象构件,定义了一个抽象接口,用于规范具体构件和装饰者的行为。ConcreteComponent是具体构件,实现了Component接口,它是被装饰的对象。Decorator是装饰者,它实现了Component接口,并持有一个指向Component的指针,用于装饰Component对象,同时还可以自定义一些额外的行为。
下面是一个使用C++语言实现的装饰者模式示例代码:
#include <iostream>
class Component {
public:
virtual void operation() = 0;
};
class ConcreteComponent : public Component {
public:
void operation() {
std::cout << "ConcreteComponent::operation()" << std::endl;
}
};
class Decorator : public Component {
public:
Decorator(Component* component) : m_component(component) {}
void operation() {
m_component->operation();
}
protected:
Component* m_component;
};
class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* component) : Decorator(component) {}
void operation() {
Decorator::operation();
std::cout << "ConcreteDecoratorA::operation()" << std::endl;
}
};
class ConcreteDecoratorB : public Decorator {
public:
ConcreteDecoratorB(Component* component) : Decorator(component) {}
void operation() {
Decorator::operation();
std::cout << "ConcreteDecoratorB::operation()" << std::endl;
}
};
int main() {
Component* component = new ConcreteComponent();
component->operation();
component = new ConcreteDecoratorA(component);
component->operation();
component = new ConcreteDecoratorB(component);
component->operation();
return 0;
}
在上述示例代码中,Component代表抽象构件,ConcreteComponent代表具体构件,Decorator代表装饰者,ConcreteDecoratorA和ConcreteDecoratorB代表具体的装饰者。装饰者类持有一个指向Component的指针,用于对Component对象进行装饰。具体的装饰者在重写operation方法时,先调用Decorator类的operation方法,再添加自己的额外行为。
在主函数中,我们先创建了一个ConcreteComponent对象,并调用了它的operation方法,这会输出"ConcreteComponent::operation()"。随后,我们使用ConcreteDecoratorA装饰这个ConcreteComponent对象,并再次调用它的operation方法,这会输出"ConcreteComponent::operation()"和"ConcreteDecoratorA::operation()"。最后,我们使用ConcreteDecoratorB再次装饰这个对象,并调用它的operation方法,这会输出"ConcreteComponent::operation()"、"ConcreteDecoratorA::operation()"和"ConcreteDecoratorB::operation()"。
5 适配器模式
- 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成另一个客户端所期望的接口。适配器模式通常用于将不兼容的类组合在一起工作,或将旧代码与新代码集成在一起。
适配器模式包括三种类型:
类适配器模式:通过继承来适配两个不兼容的接口。
对象适配器模式:通过组合一个已有的类来适配两个不兼容的接口。
接口适配器模式:通过定义一个中间接口来适配两个不兼容的接口。
下面是一个简单的对象适配器模式的示例代码,用C++实现:
#include <iostream>
using namespace std;
// 目标接口
class Target {
public:
virtual void request() = 0;
};
// 源接口
class Adaptee {
public:
void specificRequest() {
cout << "Adaptee specific request." << endl;
}
};
// 对象适配器
class Adapter : public Target {
public:
Adapter(Adaptee* adaptee) {
this->adaptee = adaptee;
}
void request() {
adaptee->specificRequest();
}
private:
Adaptee* adaptee;
};
int main() {
Adaptee* adaptee = new Adaptee();
Target* target = new Adapter(adaptee);
target->request();
return 0;
}
在上面的示例代码中,Target是目标接口,Adaptee是源接口,Adapter是对象适配器,它将Adaptee转换成Target接口,使得Target接口的客户端可以使用Adaptee的实现。具体实现中,Adapter通过组合一个Adaptee对象来实现Target接口。当客户端调用Target的request方法时,实际上是调用Adapter的request方法,而Adapter内部再调用Adaptee的specificRequest方法。这样,客户端就可以使用Target接口来访问Adaptee对象了。
需要注意的是,在适配器模式中,适配器并不是用来增加新功能或修改原有功能的,它只是将一个接口转换成另一个接口,以便让不兼容的对象能够协同工作。因此,在实际应用中,应该避免过度使用适配器模式,以免导致系统过于复杂或混乱。
6 策略模式
- 策略模式(Strategy Pattern):定义一系列算法,将每个算法都封装起来并且可以相互替换使用,使得算法可以独立于使用它的客户而变化。
策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式定义了一系列算法,将每个算法都封装起来,并使它们之间可以互换。策略模式让算法的变化独立于使用它们的客户端。
在C++中,可以通过定义一个接口来实现策略模式,并让每个具体策略类实现该接口。然后,在客户端代码中,可以根据需要创建策略对象并将其传递给需要使用算法的类。
下面是一个简单的示例代码,展示了如何在C++中使用策略模式:
#include <iostream>
class SortStrategy {
public:
virtual void sort(int arr[], int n) = 0;
};
class BubbleSortStrategy : public SortStrategy {
public:
void sort(int arr[], int n) override {
std::cout << "Sorting array using bubble sort" << std::endl;
// Bubble sort implementation
}
};
class QuickSortStrategy : public SortStrategy {
public:
void sort(int arr[], int n) override {
std::cout << "Sorting array using quick sort" << std::endl;
// Quick sort implementation
}
};
class ArraySorter {
private:
SortStrategy* strategy;
public:
ArraySorter(SortStrategy* strategy) : strategy(strategy) {}
void set_strategy(SortStrategy* strategy) {
this->strategy = strategy;
}
void sort(int arr[], int n) {
strategy->sort(arr, n);
}
};
int main() {
int arr[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
BubbleSortStrategy bubble_sort;
QuickSortStrategy quick_sort;
ArraySorter sorter(&bubble_sort);
sorter.sort(arr, n);
sorter.set_strategy(&quick_sort);
sorter.sort(arr, n);
return 0;
}
在这个例子中,SortStrategy 是一个策略接口,定义了一个 sort 方法,它是具体策略类所实现的方法。BubbleSortStrategy 和 QuickSortStrategy 是具体的策略类,它们实现了 SortStrategy 接口中的 sort 方法。 ArraySorter 类是使用策略模式的类,它有一个指向 SortStrategy 接口的指针,用于存储当前的排序策略。ArraySorter 类还定义了一个 sort 方法,该方法使用当前的排序策略来对数组进行排序。在 main 函数中,创建了一个 BubbleSortStrategy 对象和一个 QuickSortStrategy 对象,并将它们分别传递给 ArraySorter 类的构造函数和 set_strategy 方法,以指定当前的排序策略。
7 模板方法模式
- 模板方法模式(Template Method Pattern):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
8 迭代器模式
- 迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
9 组合模式
- 组合模式(Composite Pattern):将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
10 命令模式
- 命令模式(Command Pattern):将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。也可以支持可撤销的操作。
本文来自博客园,作者:mobbu,转载请注明原文链接:https://www.cnblogs.com/mobbu/p/17559583.html