美文网首页
二、7大设计原则

二、7大设计原则

作者: 木鱼_cc | 来源:发表于2018-07-07 12:58 被阅读0次
    7大原则

    1.开闭原则

    定义:Software entities like classes, modules and functions should be open for extension but closed for modification(一个软件实体如类,模块和函数应该对扩展开放,对修改关闭)

    简单来说就是:类的改动是通过增加代码进行的,而不是修改源代码

    业务员.png
    #include <iostream>
    using namespace std;
    /*
    如果想要再添加新功能,需要再次添加新的成员函数
    这样的话,会使类越来越臃肿。
    */
    class BankWorker
    {
    public:
      void save(){
         cout<<"存款"<<endl;
        }
      void transfer(){
         cout<<"转账"<<endl;
        }
      void pay(){
         cout<<"交费"<<endl;
         }
    /*
    如果我们要添加
    申购基金、网银开通、贷款等其他业务
    难道还要继续添加吗???
    */
    };
    
    int main(void)
    {
      BankWorker* bw =new BankWorker;
      bw-­‐>pay();
      bw-­‐>transfer();
      bw-­‐>save();
      delete bw;
      return 0;
    }
    

    以上对银行业务员类(BankWorker)的设计就违背了开闭原则。因为要是改动BankWorker,添加新的功能,就必须要修改该类的源代码。
    那么,如何使这段代码符合开闭原则呢?

    #include <iostream>
    using namespace std;
    class AbBankWorker
    {
    public:
    /* 纯虚函数 用来抽象 银行业务员的业务 */
      virtual void doBusiness() = 0;
    };
    
    class saveBankWorker:publicAbBankWorker
    {
    public:
      virtual void doBusiness(){
        cout<<"存款"<<endl;
      }
    };
    
    class transBankWorker:publicAbBankWorker
    {
    public:
      virtual void doBusiness(){
        cout<<"转账"<<endl;
      }
    };
    
    class payBankWorker:publicAbBankWorker
    {
      virtual void doBusiness(){
       cout<<"付款"<<endl;
      }
    };
    /*
    我们现在想开通 基金办理 业务员
    那么只需要再集成基类,实现业务虚函数即可
    */
    class fundBankWorker:publicAbBankWorker
    {
      virtual void doBusiness(){
      cout<<"基金办理"<<endl;
      }
    };
    int main(void)
    {
      /*
       产生多态的3个必要条件
       1.有继承,比如,saveBankWorker继承了AbBankWorker
       2.要有重写,这里AbBankWorker的doBusiness()接口被重写
       3.父类指针指向子类对象
    */
    
      AbBankWorker *abw=NULL;
      abw = new saveBankWorker;
      abw­‐>doBusiness();
      delete abw;
      abw = NULL;
    
      abw = new transBankWorker;
      abw-‐>doBusiness();
      delete abw;
      abw = NULL;
    
      abw = new payBankWorker;
      abw‐>doBusiness();
      delete abw;
      abw = NULL;
    
      abw = new fundBankWorker;
      abw‐>doBusiness();
      delete abw;
      abw = NULL;
    
      return 0;
    }
    

    这样,如果我们给银行业务员添加业务,那么无需修改原来的类中代码,而是通过拓展添加类的方式来搞定,实际上是利用了多态的特性,这样就符合了开闭原则。

    2.依赖倒置原则

    定义:High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

    翻译过来,包含三层含义:

    • 高层模块不应该依赖低层模块,两者都应该依赖其抽象
    • 抽象不应该依赖细节
    • 细节应该依赖抽象

    在具体编程语言中表现就是

    • 抽象就是指接口或抽象类
    • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系通过接口或抽象类产生的;
    • 接口或抽象类不依赖于现实类
    • 实现类依赖接口或抽象类

    更加精简的定义就是“面向接口编程”——OOD(Object-Oriented Design,面向对象设计)的精髓之一

    2.1案例
    传统设计

    传统的过程式设计倾向于使高层次的模块依赖于低层次的模块,抽象层依赖于具体的层次。

    image.png

    如图分析,最上层是高层业务逻辑层,让张三区开奔驰,依赖于创建张三这个类,开奔驰就创建奔驰这个类,接着在张三类里面创建成员函数;当开BMW时,就又要在张三类中创建另一个成员函数。同理,当李四需要去开奔驰或宝马时,就需要重新创建李四类,添加开奔驰和宝马的方法,具体代码如下:

    class Benz
    {
    public:
        void run() {
            cout << "奔驰启动了" << endl;
        }
    };
    
    class BMW
    {
    public:
        void run() {
            cout << "宝马启动了" << endl;
        }
    };
    
    class Zhang3
    {
    public:
        void driveBenz(Benz *b) {
            b->run();
        }
    
        void driveBMW(BMW *b)
        {
            b->run();
        }
    };
    
    //业务
    int main(void)
    {
    #if 0
        //张三去开奔驰
        Benz  *benz = new Benz;
        Zhang3 *z3 = new Zhang3;
        z3->driveBenz(benz);
    
        //张三去开宝马
        BMW * bmw = new BMW;
        z3->driveBMW(bmw);
    
        //李四.....
        //....
            return 0;
    }
    

    依赖倒转后:

    依赖倒置

    将人driver和车car变成抽象类,利用接口耦合

    
    //------抽象层------
    
    class Car
    {
    public:
        virtual void run() = 0;
    };
    
    class Driver {
    public:
        virtual void drive(Car *car) = 0;
    };
    
    void travel(Driver *d, Car *c)
    {
        d->drive(c);
    }
    
    
    
    //实现层-----
    class Zhang3 :public Driver{
    public:
        virtual void drive(Car *car)
        {
            cout << "涨3 开车了" << endl;
            car->run();
        }
    };
    class Li4 :public Driver{
    public:
        virtual void drive(Car *car)
        {
            cout << "Li4 开车了" << endl;
            car->run();
        }
    };
    
    class Benz :public Car
    {
    public:
        virtual void run() {
            cout << "benz 启动了" << endl;
        }
    };
    class BMW :public Car
    {
    public:
        virtual void run() {
            cout << "BMW 启动了" << endl;
        }
    };
    
    //业务
    int main(void)
    {
        //张三去开奔驰
        Car * benz = new Benz;
        Driver* zang3 = new Zhang3;
    
        zang3->drive(benz);
    
        //li4 区开宝马
        Car * bmw = new BMW;
        Driver *li4 = new Li4;
    
        li4->drive(bmw);
    
        
        return 0;
    }
    
    依赖倒置2

    传统的设计模式通常是自顶向下逐级依赖,这样,底层模块,中间层模块和高层模块的耦合度极高,若任意修改其中的一个,很容易导致全面积的修改,非常麻烦,那么依赖倒转原则利用多态的先天特性,对中间抽象层进行依赖,这样,底层和高层之间进行了解耦合

    2.2案例2——电脑组装
    #define  _CRT_SECURE_NO_WARNINGS 
    #include <iostream>
    
    using namespace std;
    
    //抽象层--------
    class CPU
    {
    public:
        virtual void caculate() = 0;
    };
    
    class Card
    {
    public:
        virtual void display() = 0;
    };
    
    class Memory
    {
    public:
        virtual void storage() = 0;
    };
    
    //架构类
    class Computer
    {
    public:
        Computer(CPU *cpu, Card*card, Memory * mem)
        {
            this->cpu = cpu;
            this->card = card;
            this->mem = mem;
        }
    
        void work() {
            cpu->caculate();
            card->display();
            mem->storage();
        }
    private:
        CPU *cpu;
        Card*card;
        Memory *mem;
    };
    
    
    //  实现层
    class IntelCPU :public CPU{
    public:
        virtual void caculate()  {
            cout << "Intelcpu 工作了" << endl;
        }
    };
    
    class NvidiaCard :public Card
    {
    public:
        virtual void display() {
            cout << "N卡工作了" << endl;
        }
    };
    
    class XSMem :public Memory {
    public:
        virtual void storage()  {
            cout << "XS存储了" << endl;
        }
    };
    
    
    //高层业务
    int main(void)
    {
        CPU *cpu = new IntelCPU;
        Card *card = new NvidiaCard;
        Memory *mem = new XSMem;
        Computer *com = new Computer(cpu, card, mem);
    
    
        com->work();
    
        delete cpu;
        delete card;
        delete mem;
        delete com;
        
        return 0;
    }
    

    3.合成复用原则

    如果继承和组合都能够完成功能的添加,那么优先使用组合(依赖)

    合成复用原则

    如图,如果想对Cat类增加功能,根据开闭原则,我们只能通过创建AdvCat类进行添加,如果使用继承,那么AdvCat在创建实例后很庞大,而且对其父类的修改也会受到影响

    #define  _CRT_SECURE_NO_WARNINGS 
    #include <iostream>
    
    using namespace std;
    
    class Cat
    {
    public:
        void sleep() {
            cout << " 小猫睡觉了" << endl;
        }
    };
    
    //向给猫添加一个功能, 创建一个新的猫 既能够睡觉,又能吃东西
    //通过继承的方式完成
    class AdvCat :public Cat{
    public:
        void eatAndSleep() {
            cout << "吃东西" << endl;
            sleep();
        }
    };
    
    
    //使用组合的方式来添加小猫的吃东西方法
    //使用组合的方式,降低了AdvCat2 和Cat的耦合度, 跟Cat的父类没有任何关系,
    //只跟Cat的sleep方法有关系
    class AdvCat2
    {
    public:
        AdvCat2(Cat *cat)
        {
            this->cat = cat;
        }
    
        void eatAndSleep() {
            cout << "吃东西" << endl;
            cat->sleep();
        }
    private:
        Cat *cat;
    };
    
    
    int main(void)
    {
        Cat c;
        c.sleep();
    
        AdvCat ac;
        ac.eatAndSleep();
    
        cout << "----- " << endl;
    
        AdvCat2 ac2(&c);
        ac2.eatAndSleep();
        
        return 0;
    }
    

    4.迪米特法则(最少知识原则)

    定义:一个对象应该对其他对象有最少的了解。

    通俗地讲,一个类应该对自己需要耦合或者调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂和我没有关系。

    迪米特法则

    相关文章

      网友评论

          本文标题:二、7大设计原则

          本文链接:https://www.haomeiwen.com/subject/wvtiuftx.html