zoukankan      html  css  js  c++  java
  • 第2章 面向对象的设计原则(SOLID):4_接口隔离原则(ISP)

    4. 接口隔离原则(Interface Segregation Principle,ISP)

    4.1 定义

    (1)使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。类间的依赖关系应该建立在最小接口

    (2)接口尽量细化,同时接口中的方法尽量少。每个接口中只包含一个客户端(如子模块或业务逻辑类)所需的方法即可,这种机制也称为“定制服务”,即为不同的客户端提供宽窄不同的接口。

    (3)为接口添加了不必要的方法,这叫接口污染。这对于实现类来讲,就是一种污染,他们会被迫去实现这些不必要的功能方法。并且当接口发生改变时,他们也不得不跟着改变。

    4.2 接口隔离原则和单一职责原则的区别

    (1)单一职责注意的是职责,是从业务逻辑上划分的。而接口隔离要求接口要尽量少。如有一个向外提供查询服务的,但提供的接口很多,有普通权限和高级权限的查询方法。这按单一职责原则是允许的,只提供单一职责,即查询。但按照接口隔离原则是不允许的。应按权限提供专门的接口给不同权限的客户端。

    (2)接口隔离原则讲的就是同一个角色提供宽、窄不同的接口,以对付不同的客户端。

    4.3 使用接口原则的注意事项

    (1)接口尽量小,但要有限度。对接口进行细行可以提高设计灵活性,但如果过小,则会造成接口数量过多,使设计模式复杂化

    (2)为依赖接口的类定制服务,只暴露给调用它的类所需要的方法,不需要的则隐藏起来。

    (3)提高内聚,减少对外交互。使接口用最小的方法去完成最多的事情。具体要求就是,在接口中尽量少提供public方法,接口是对外的承诺,承诺地越少对系统开发越有利,变更的风险也就越少,同时也有利于降低成本。

    【编程实验】接口隔离的例子

      ①Manager类代表管理工人的管理者。

      ②有两类工人,普通和高效的,他们都需要吃饭和工作

      ③如果这里来了一个机器人(Robot),如果保持现有设计,让Robot去实现IWork接口,就会被迫去实现吃饭的功能,这种情况下IWorker被认为是一个被污染了的接口。需重构,细化出3个接口,一个IWorkable(工作)、IFeedable(吃饭)和IRechargeable(充电)。

      ④工人类去实现IWorkable和IFeedable接口。Robot只实现IWorkable接口和 IRechargeable接口。

    //当加入Robot类后,一个被污染的接口设计

     

    //重构后符合接口隔离原则的设计

     

    //面向对象设计原则:ISP接口隔离原则
    //细化接口
    
    #include <stdio.h>
    
    //IWorkable接口:工作
    class IWorkable
    {
    public:
        virtual void work() = 0;
    };
    
    //IFeedable接口:吃饭
    class IFeedable
    {
    public:
        virtual void eat() = 0;
    };
    
    //IRechargeable接口:充电
    class IRechargeable
    {
    public:
        virtual void recharge() = 0;
    };
    
    //CommonWorker类:普通工人
    class CommonWorker : public IWorkable, public IFeedable
    {
    public:
        void eat(){printf("Common Worker eat()...
    ");}
        void work(){printf("Common Worker work()...
    ");}   
    };
    
    //EfficentWork类:高效工人
    class EfficentWork : public IWorkable, public IFeedable
    {
    public:
        void eat(){printf("Efficent Worker eat()....
    ");}
        void work(){printf("Efficent Worker work()...
    ");}   
    };
    
    //Robot类:机器人
    class Robot : public IWorkable, public IRechargeable
    {
    public:
        void recharge(){printf("Robot recharge()...
    ");}
        void work(){printf("Robot work()...
    ");}   
    };
    
    //Manager类:管理者
    class Manager
    {
    private:
        IWorkable* worker;
    public:
        void setWorker(IWorkable* w){worker = w;}
        void manage(){worker->work();}
    };
    int main()
    {
        
        CommonWorker cmw;
        EfficentWork efw;
        Robot rb;
        
        Manager mn;
        
        //管理员让普通工人工作
        mn.setWorker(&cmw);
        mn.manage();
        
        //管理员让高效工人工作
        mn.setWorker(&efw);
        mn.manage();
        
        //管理员让机器人工作
        mn.setWorker(&rb);
        mn.manage();
        
        return 0;
    }

    4.4 最佳实践

    (1)一个接口只服务于一个子模块或业务逻辑

    (2)通过业务逻辑压缩接口中的public方法,以提高内聚

    (3)己经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化。

  • 相关阅读:
    关于键盘触发事件和屏幕触发事件的问题
    andriod开发之自动开关机实现代码
    Android之Gallery的两种使用方法
    关于自定义View时,画图形和图片时抗锯齿的使用的问题
    android:descendantFocusability用法简析
    MVC访问Views文件下的静态文件
    iframe框架之间js方法相互调用及数据传递
    省、市、地区联动选择JS封装类PCASClass.js
    MVC自定义URL地址参数
    C#字符窜中转义小括号
  • 原文地址:https://www.cnblogs.com/5iedu/p/5476757.html
Copyright © 2011-2022 走看看