一些常用的软件设计模式

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 是抽象产品类,ConcreteProductAConcreteProductB 是具体产品类。Factory 是抽象工厂类,ConcreteFactoryAConcreteFactoryB 是具体工厂类。在 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):将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。也可以支持可撤销的操作。
posted @ 2023-07-17 11:27  mobbu  阅读(68)  评论(0编辑  收藏  举报