设计模式八股

发布时间 2023-10-02 18:20:10作者: timeMachine331

UML-Unified Modeling Language 统一建模语言,又称标准建模语言。是用来对软件密集系统进行可视化建模的一种语言。

进行设计时经常使用这种方法进行建模

 

创建型模式:

单例模式:

局部静态变量懒汉式,在第一次调用函数时才对其进行初始化,因为局部静态变量只能被初始化一次,即便有多线程对其初始化操作,也只有其中一个线程会成功,其他线程对其进行的初始化都会无效。

#include <bits/stdc++.h>

using namespace std;

class Singleton{
    public:
        static Singleton& getInstance(){
            static Singleton instance;
            return instance;
        }
    private:
        Singleton() = default;
        ~Singleton() = default;
        Singleton(const Singleton&) = delete;
        Singleton& operator=(const Singleton&) = delete;
        Singleton(Singleton&&) = delete;
        Singleton& operator=(Singleton&&) = delete;
};


int main(){
    Singleton* p1 = &Singleton::getInstance();
    Singleton* p2 = &Singleton::getInstance();

    if(p1 == p2){
        cout << "same" << endl;
    }

    return 0;
}

 

抽象工厂模式:

https://www.zhihu.com/search?type=content&q=%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82

定义抽象产品(鼠标键盘)、具体产品(联想鼠标联想键盘、雷蛇鼠标雷蛇键盘)、抽象工厂(可以生产鼠标键盘)、具体工厂(联想工厂、雷蛇工厂)。

具体产品继承抽象产品,具体工厂继承抽象工厂并提供接口。

客户不用知道生产的具体产品是什么类也不用知道这个工厂是什么类,调用这个抽象工厂类型的指针就行了。指针指向哪个派生类具体工厂就生产哪个工厂的某一类产品

优点:灵活可靠、方便维护拓展起来也比较轻松。

 

#include <bits/stdc++.h>

using namespace std;

class Abstract_keyboard{
    public:
        virtual void showTag() = 0;
};

class Abstract_mouse{
    public:
        virtual void showTag() = 0;

};

class Lenovo_keyboard: public Abstract_keyboard{
    public:
        void showTag() override{
            cout << "this is lenovo keyboard" << endl;
        }
};

class Lenovo_mouse: public Abstract_mouse{
    public:
        void showTag() override{
            cout << "this is lenovo mouse" << endl;
        }
};

class Razer_keyboard: public Abstract_keyboard{
    public:
        void showTag() override{
            cout << "this is razer keyboard" << endl;
        }
};

class Razer_mouse: public Abstract_mouse{
    public:
        void showTag() override{
            cout << "this is razer mouse" << endl;
        }
};

class Abstract_factory{
    public:
        virtual Abstract_keyboard* createKeyboard() = 0;
        virtual Abstract_mouse* createMouse() = 0;
};

class Lenovo_factory: public Abstract_factory{
    Abstract_keyboard* createKeyboard() override{
        return new Lenovo_keyboard();
    }
    Abstract_mouse* createMouse() override{
        return new Lenovo_mouse();
    }
};

class Razer_factory: public Abstract_factory{
    Abstract_keyboard* createKeyboard() override{
        return new Razer_keyboard();
    }
    Abstract_mouse* createMouse() override{
        return new Razer_mouse();
    }
};

int main(){
    Abstract_factory* p1 = new Lenovo_factory();
    p1->createKeyboard()->showTag();
    p1->createMouse()->showTag();


    p1 = new Razer_factory();
    p1->createKeyboard()->showTag();
    p1->createMouse()->showTag();


    return 0;
}

 

 

结构型模式:

装饰器模式:

https://zhuanlan.zhihu.com/p/92516705

  • 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有类的一个包装。
  • 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
  • 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
  • 何时使用:在不想增加很多子类的情况下扩展类。
  • 例如:咖啡由咖啡豆加工而来,咖啡又扩展出了美式咖啡,拿铁,摩卡。而美式咖啡,拿铁,摩卡可以在咖啡的基础上做一些属性的装饰来完成,如他们的价格不一样,产地也不一样。为了避免继承自咖啡类,我们用装饰器模式来实现该需求。

怎么用?首先有个咖啡豆基类,然后定义一个装饰器基类,之后通过继承装饰器同时又把原始基类指针作为已经存在的成员变量,对其进行动态的修改与撤销,作为继承的一种替代方案。

优点:比较灵活

缺点:代码复杂了。

 

行为型模式:

观察者模式:

#include <bits/stdc++.h>

using namespace std;

class Subject;

class Observer{
    public:
        Observer(const shared_ptr<Subject>& p): m_subject(p){}

        virtual void update() = 0;
        virtual ~Observer() = default;

    public:
        weak_ptr<Subject> m_subject;
};


class Subject{
    public:
        Subject() : m_value(0){}

        void updateValue(int n){
            m_value = n;
        }
        
        int getValue(){
            return m_value;
        }

        void sendNotify(){
            for(auto o : m_observer){
                o->update();
            }
        }

        void append(const shared_ptr<Observer>& o){
            m_observer.insert(o);
        }


        void erase(const shared_ptr<Observer>& o){
            m_observer.erase(o);
        }
    private:
        int m_value;
        set<shared_ptr<Observer>> m_observer;

};

class ObserverA: public Observer{
    public:
        //using Observer::Observer;
        /*
        using A::A; // c++里构造函数默认是不能被继承的,
        当确定派生类使用基类的构造函数也不会出问题时,可以明确指出要继承基类的构造函数,
        这个using A::A; 就是告诉编译器,这个派生类要继承基类的构造函数
        */
        //注意这里的列表初始化需要对Observer不能对m_subject
        ObserverA(const shared_ptr<Subject>& p): Observer(p){}
        void update() override{
            if(const auto p = m_subject.lock()){
                cout << "A " << p->getValue() << endl;
            }
        }
};

class ObserverB: public Observer{
    public:
        //using Observer::Observer;
        ObserverB(const shared_ptr<Subject>& p): Observer(p){}
        void update() override{
            if(const auto p = m_subject.lock()){
                cout << "B " << p->getValue() << endl;
            }
        }
};


int main() {
  auto subject = std::make_shared<Subject>();
  auto a = std::make_shared<ObserverA>(subject);
  auto b = std::make_shared<ObserverB>(subject);

  subject->append(a);
  subject->append(b);

  subject->updateValue(3);
  subject->sendNotify();  // subject_ value in A: 3\nsubject value in B: 3\n
}

 

模板方法模式:

我有煮茶和煮咖啡两个对象化的事件。

两个都需要做的动作有烧水,倒入杯子

煮茶要做的把茶叶倒进杯子、加柠檬

煮咖啡要做的把咖啡倒入杯子加糖和牛奶。

只是一部分的动作需要进行重写,另一部分可以复用,最后调用模板方法函数即可。

  • 在基类定义一个包含多个操作的方法,每个操作在派生类中实现,基类的这个方法就是模板方法。在 C++ 中这种手法称为 NVI(non-virtual interface),模板方法是一个非虚函数,其中的操作为虚函数,并且作为私有成员不暴露给外部
// Template method
#include <iostream>
using namespace std;


class CoffeineBeverage {
public:
    void prepare_recipe() {
        boil_water();
        brew();
        pour_in_cup();
        add_condiments();
    }
private:
    virtual void brew() {
        cout << "Dripping something through filter." << endl;
    }

    virtual void add_condiments() {
        cout << "Adding something." << endl;
    }
protected:
    void boil_water() {
        cout << "Boiling water." << endl;
    }
    
    void pour_in_cup() {
        cout << "pouring into cup." << endl;
    }
    

};

class Coffee : public CoffeineBeverage{
private:
    virtual void brew() {
        cout << "Dripping coffe through filter." << endl;
    }

    virtual void add_condiments() {
        cout << "Adding sugar and mile." << endl;
    }
};

class Tea : public CoffeineBeverage {
private:
    virtual void brew() {
        cout << "Dripping tea through filter." << endl;
    }

    virtual void add_condiments() {
        cout << "Adding lemon." << endl;
    }
};


/************************* TEST ******************************/
int main(int argc, char **argv)
{
    //CoffeineBeverage *cb = new Coffee;
    //CoffeineBeverage *cb2 = new Tea;
  
    unique_ptr<Make> p = make_unique<makeCoffee>();

    cout << "Coffee:" << endl;
    p->prepare_recipe();
    cout << "Tea:" << endl;
    cb2->prepare_recipe();

    return 0;
}