设计模式的详细介绍

目录

六大原则

(1)单一职责原则:

(2)开闭原则:

(3)里氏替换原则:

(4)依赖倒置原则:

(5)迪米特法则:

(6)接口隔离原则:

总结

单例模式

工厂模式

简单工厂模式

工厂方法模式

抽象工厂模式

建造者模式

代理模式


六大原则

(1)单一职责原则:

  • 类的职责应该单一,一个方法只做一件事。职责划分清晰明了,每次改动到最小单位的类或者方法。
  •  使用建议:两个完全不一样的功能不能放在一个类中,一个类应该是一组相关性很高的函数、数据的封装。
  •  用例:网络聊天:应该分割为网络通信类和聊天类。

(2)开闭原则:

  • 对扩展开放,对修改封闭。
  • 使用建议:对软件实体的改动,最好用扩展而非修改的方式。
  • 用例:超市卖货:商品促销价格--不是修改商品原来的价格,而是新增促销价格。

(3)里氏替换原则:

  • 就是只要父类能出现的地方,子类就可以出现,而且替换为子类也不会产生任何错误或者异常。
  • 在继承类时,务必重写父类中所有的方法,尤其需要注意父类的protected方法,子类尽量不要暴露自己的public方法供外界调用。
  •  使用建议:子类必须完全实现父类的方法,子类可以有自己的个性。覆盖或实现父类的方法时,输入参数可以被放大,输出可以缩小。
  • 用例:跑步运动员类-会跑步,子类长跑运动员-会跑步且擅长长跑,子类短跑运动员-会跑步且擅长短跑。

(4)依赖倒置原则:

  • 高层模块不应该依赖底层模块,两者都应该依赖其抽象,不可分割的原子逻辑就是底层模式,原子逻辑组装成的就是高层模块。
  • 模块间依赖通过抽象(接口)发生,具体类之间不直接依赖。
  • 使用建议:每个类都尽量有抽象类,任何类都不应该从具体类派生,尽量不要重写基类的方法。结合里氏替换原则使用。
  •  用例:奔驰司机类-只能开奔驰;司机类-给什么车就开什么车;开车的人:司机--依赖于抽象。

(5)迪米特法则:

  • 尽量减少对象之间的交互,从而减少类之间的耦合。一个对象应该对其他对象有最少的了解。对类的低耦合提出了明确的要求:只和直接的朋友交流,朋友之间也是有距离的。自己的就是自己的(如果一个方法放在本类中,既不增加类间关系,也不对本类产生负面影响,那就放置在本类中)。
  •  用例:老师让班长点名--老师给班长一个名单,班长完成点名勾选,返回结果,而不是班长点名,老师勾选。

(6)接口隔离原则:

  • 客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。
  • 使用建议:接口设计尽量精简单一,也不要对外暴露没有实际意义的接口。
  • 用例:修改密码,不应该提供修改用户信息的接口,而就是单一的最小修改密码的接口,更不要暴露数据库操作。

总结

        从整体上来理解六大设计原则,可以简单地概括为一句话,用抽象构建框架,用实现扩展细节,具体到每一条设计原则,则对应一条注意事项:

        (1)单一职责原则:实现类要职责单一;

        (2)里氏替换原则:不要破坏继承体系;

        (3)依赖倒置原则:要面向接口编程;

        (4)接口隔离原则:设计接口时要精简单一;

        (5)迪米特法则:要降低耦合;

        (6)开闭原则(总纲):要对扩展开放,对修改关闭。

单例模式

        一个类只能创建一个对象,即单例模式,该设计模式保证系统中该类只存在一个实例,并提供一个全局访问点,该实例被所有的程序模块共享。

        单例模式有两种实现模式:

  • 饿汉模式:程序启动时就会创建出一个唯一的实例对象,因为单例对象已经确定,所以比较适用于多线程环境中,多线程获取单例对象不需要加锁,可以有效避免资源竞争,提高性能。
  • 懒汉模式:第一次使用要使用单例对象的时候创建实例对象。如果单例对象构造特别耗时或者耗费资源,可以选择懒汉模式。(c++11 static local variables特性以确保c++11起,静态变量将能够在满足线程安全的前提下唯一被构造和析构)
#include 
#include 
#include 
using namespace std;

// 单例模式

// 饿汉模式
// class Singleton
// {
// public:
//     Singleton(const Singleton&) = delete;
//     Singleton& operator=(const Singleton&) = delete;

//     static Singleton& getInstance()
//     {
//         return singleton;
//     }

//     void name()
//     {
//         cout << _name << endl;
//     }

// private:
//     Singleton() {}
//     ~Singleton() {}
//     string _name = "Singleton";
//     static Singleton singleton;
// };

// Singleton Singleton::singleton;

// 懒汉模式
class Singleton
{
public:
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton &) = delete;

    static Singleton& getInstance()
    {
        static Singleton ston;
        return ston;
    }

    void name()
    {
        cout << _name << endl;
    }

private:
    Singleton() {}
    ~Singleton() {}
    string _name = "Singleton";
};

int main()
{
    Singleton::getInstance().name();
    return 0;
}

工厂模式

        工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象,以此实现创建-使用的分离。

简单工厂模式

        实现由一个工厂对象通过类型决定创建出来指定产品类的实例。比如说有个工厂可以生产出多种水果,当客户需要某种水果时,告诉给工厂,工厂就可以根据客户提供的信息生产出特定的水果,当新增产品时,工厂内部需要添加新产品的生产方式。

#include 
#include 
#include 

using namespace std;

class Fruit
{
public:
    virtual void show() = 0;
};

class Apple : public Fruit
{
public:
    void show() override
    {
        cout << "apple" << endl;
    }
};

class Banana : public Fruit
{
public:
    void show() override
    {
        cout << "banana" << endl;
    }
};

class FruitFactory
{
public:
    static shared_ptr create(const string &name)
    {
        if(name == "apple") { return make_shared(); }
        else if(name == "banana") { return make_shared(); }
        else { throw logic_error("没有这种水果"); }
    }
};

int main()
{
    shared_ptr f = FruitFactory::create("apple");
    f->show();
    f = FruitFactory::create("banana");
    f->show();
    return 0;
}

优点:简单粗暴,直观易懂。使用一个工厂生产同一个等级结构下的任意产品。

缺点:(1)所有东西生产在一起,产品太多会导致代码量庞大。

            (2)开闭原则遵循的不是太好,要新增产品必须修改工厂方法。

工厂方法模式

        在简单工厂模式下新增多个工厂,多个产品,每个产品对应一个工厂。假设有A,B两种产品,那么就开两个工厂A,B,工厂A生产产品A,工厂B生产产品B。

​
#include 
#include 
#include 

using namespace std;

class Fruit
{
public:
    virtual void show() = 0;
};

class Apple : public Fruit
{
public:
    void show() override
    {
        cout << "apple" << endl;
    }
};

class Banana : public Fruit
{
public:
    void show() override
    {
        cout << "banana" << endl;
    }
};

class FruitFactory
{
public:
    virtual shared_ptr create() = 0;
};

class AppleFactory : public FruitFactory
{
public:
    shared_ptr create() override { return make_shared(); } 
};

class BananaFactory : public FruitFactory
{
public:
    shared_ptr create() override { return make_shared(); } 
};

int main()
{
    shared_ptr ff(new AppleFactory());
    ff->create()->show();
    ff.reset(new BananaFactory());
    ff->create()->show();
    return 0;
}

​

优点:(1)减轻了工厂类的负担,将其他产品的生产交给指定的工厂来进行。

           (2)开闭原则遵循较好,添加新产品时只需要新增产品的工厂即可。

缺点:对于某种可以形成一组产品族的情况处理较为复杂,需要创建大量的工厂类。

抽象工厂模式

        ⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问 题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势 必会增加系统的开销。此时,我们可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级 结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思想。

#include 
#include 
#include 

using namespace std;

class Fruit
{
public:
    virtual void show() = 0;   
};

class Animal
{
public:
    virtual void voice() = 0;
};

class Apple : public Fruit
{
public:
    void show() override { cout << "苹果" << endl; }
};

class Banana : public Fruit
{
public:
    void show() override { cout << "香蕉" << endl; }
};

class Lamp : public Animal
{
public:
    void voice() override { cout << "咩咩咩" << endl; }
};

class Dog : public Animal
{
public:
    void voice() override { cout << "汪汪汪" << endl; }
};

class Factory 
{
public:
    virtual shared_ptr createFruit(const string &name) = 0;
    virtual shared_ptr createAnimal(const string &name) = 0;
};

class FruitFactory : public Factory
{
    shared_ptr createFruit(const string &name) override
    {
        if (name == "苹果") { return make_shared(); }
        else if(name == "香蕉") { return make_shared(); }
        else throw logic_error("没有这种水果");
    }
    shared_ptr createAnimal(const string &name) override
    { throw logic_error("水果工厂不能创建动物"); }
};


class AnimalFactory : public Factory
{
    shared_ptr createFruit(const string &name) override
    { throw logic_error("动物工厂不能创建水果"); }
    shared_ptr createAnimal(const string &name) override
    {   
        if (name == "山羊") { return make_shared(); }
        else if(name == "小狗") { return make_shared(); }
        else throw logic_error("没有这种动物"); 
    }
};

class FactoryProducer
{
public:
    static shared_ptr createFactory(const string &name)
    {
        if(name == "水果") { return make_shared(); }
        else if(name == "动物") { return make_shared(); }
        else throw logic_error("没有这种工厂");
    }
};

int main()
{
    shared_ptr fac = FactoryProducer::createFactory("水果");
    fac->createFruit("苹果")->show();
    fac->createFruit("香蕉")->show();
    fac = FactoryProducer::createFactory("动物");
    fac->createAnimal("山羊")->voice();
    fac->createAnimal("小狗")->voice();
    return 0;
}

适用于生产多个工厂系列产品衍生的设计模式,增加新的产品等级结构复杂,需要对原 有系统进⾏较⼤的修改,甚⾄需要修改抽象层代码,违背了“开闭原则”。

建造者模式

  • 建造者模式是⼀种创建型设计模式, 使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象,能够将⼀个复杂的对象的构建与它的表⽰分离,提供⼀种创建对象的最佳⽅式。主要⽤于解决对象的构建过于复杂的问题。
  • 核心类:(1)抽象产品类;(2)具体产品类:一个具体的产品对象类;(3)抽象Builder类:创建一个产品对象所需的各个部件的抽象接口;(4)具体产品的Builder类:实现抽象接口,构建各个部件;(5)指挥者Director类:统一组建过程,提供给调用者使用,通过指挥者来构建产品。
#include 
#include 
#include 

using namespace std;

class Computer
{
public:
    void setBoard(const string &board)
    {
        _board = board;
    }

    void setDisplay(const string &display)
    {
        _display = display;
    }

    void show()
    {
        string computer = "Computer{\n";
        computer += "\tBoard:" + _board + "\n";
        computer += "\tDisplay:" + _display + "\n";
        computer += "\tOs:" + _os + "\n";
        computer += "}\n";
        cout << computer;
    }

    virtual void setOs() = 0;

protected:
    string _board;
    string _display;
    string _os;
};

class MacBook : public Computer
{
public:
    void setOs() override
    {
        _os = "Mac";
    }
};

class Builder
{
public:
    virtual void buildBoard(const string &board) = 0;
    virtual void buildDisplay(const string &display) = 0;
    virtual void buildOs() = 0; 
    virtual shared_ptr build() = 0;
};

class MacBuilder : public Builder
{
public:
    MacBuilder() : _computer(new MacBook()) {}
    void buildBoard(const string &board) override
    {
        _computer->setBoard(board);
    }
    void buildDisplay(const string &display) override
    {
        _computer->setDisplay(display);
    }
    void buildOs() override
    {
        _computer->setOs();
    } 

    shared_ptr build() override
    {
        return _computer;
    }
private:
    shared_ptr _computer;
};

class Director
{
public:
    Director(Builder * builder) : _builder(builder) {}
    void Construct(const string &board, const string &display)
    {
        _builder->buildBoard(board);
        _builder->buildDisplay(display);
        _builder->buildOs();
    } 
private:
    shared_ptr _builder;
};

int main()
{
    Builder *builder = new MacBuilder();
    shared_ptr director(new Director(builder));
    director->Construct("华硕主板", "三星显示器");
    shared_ptr computer = builder->build();
    computer->show();
    return 0;
}

代理模式

  • 代理模式指代理控制对其他对象的访问, 也就是代理对象控制对原对象的引⽤。在某些情况下,⼀个对象不适合或者不能直接被引⽤访问,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤。
  • 代理模式的结构包括⼀个是真正的你要访问的对象(⽬标类)、⼀个是代理对象。⽬标对象与代理对象实现同⼀个接⼝,先访问代理类再通过代理类访问⽬标对象。
  • 以租房为例,房东将房⼦租出去,但是要租房⼦出去,需要发布招租启⽰, 带⼈看房,负责维修,这些⼯作中有些操作并⾮房东能完成,因此房东为了图省事,将房⼦委托给中介进⾏租赁。
  • 代理模式实现:
#include 
#include 
#include 

using namespace std;

class RentHouse
{
public:
    virtual void rentHouse() = 0;
};

class Landlord : public RentHouse
{
public:
    void rentHouse() override 
    {
        cout << "把房子租出去" << endl;
    }
};

class Intermediary : public RentHouse
{
public:
    void rentHouse() override
    {
        cout << "发布招租启示\n";
        cout << "带人看房\n";
        _landlord.rentHouse();
        cout << "租后维修\n";
    }
private:
    Landlord _landlord;
};

int main()
{
    Intermediary im;
    im.rentHouse();
    return 0;
}

你可能感兴趣的:(设计模式的详细介绍)