文档章节

面向对象的六大原则之 接口隔离原则——ISP

o
 osc_ugeljcjn
发布于 2019/07/22 06:46
字数 1646
阅读 5
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

ISP = Interface Segregation Principle
 
ISP的定义如下:
1、客户端不应该依赖他不需要的接口
2、一个类对另外一个类的依赖性应该是建立在最小的接口上
3、不应当将不同的接口合并在一起,形成一个臃肿的大接口,这是对接口的污染
4、使用多个专门的接口要比使用单一的总接口要好
 
 
ISP的几个使用原则
1、根据接口隔离原则拆分接口时,首先必须满足单一职责原则: 没有哪个设计可以十全十美的考虑到所有的设计原则,有些设计原则之间就可能出现冲突,就如同单一职责原则和接口隔离原则,一个考虑的是接口的职责的单一性,一个考虑的是方法设计的专业性(尽可能的少),必然是会出现冲突。在出现冲突时,尽量以单一职责为主,当然这也要考虑具体的情况。
2、提高高内聚: 提高接口,类,模块的处理能力,减少对外的交互。比如你给杀手提交了一个订单,要求他在一周之内杀一个人,一周后杀手完成了任务,这种不讲条件完成任务的表现就是高内聚。具体来说就是:要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险就越小,也有利于降低成本。
3、定制服务: 单独为一个个体提供优良服务(只提供访问者需要的方法)。
4、接口设计要有限度: 根据经验判断
 
 
接口隔离原则和单一职责原则就是一个硬币的两面,他们说的其实是一回事。
只是接口隔离原则是站在服务调用者角度看问题,单一职责原则是站在服务提供者的角度看。
 
 
===========================================================================================
契约是怎么回事呢?
契约就是在说两件事,甲方在契约里说我不会多要,乙方会在契约里说我不会少给。
乙方的不会少给是比较容易做到的,因为当一个类实现一个接口的时候,他必须要实现接口里的所有方法。如果你不想实现所有的方法,你留下了抽象方法,那你这个类就是抽象类,不能被实例化,即你不是一个完整的服务提供者。所以说乙方不会少给,是强制性的。
甲方不会多要是软性的规定,他是个设计上的东西,需要我们用一些设计原则去约束和控制大家写代码。因为编译器是能检测出乙方是不是少给,没法检查出来甲方是不是多要了。
 
那么我怎么知道甲方有没有多要呢?很简单,就看传递给调用者接口类型里,有没有一直没有被调用到的函数成员,如果有,就说明传递进来的接口类型太大了(太胖了),换句话说 胖接口就是这个接口是由两个或两个以上本质不同的小一点接口合并起来的,把大接口传递进来,只能一部分接口被调用到,另一部分就多余出来了。
根据胖接口的产生原因不同,违反接口隔离原则可能带来的不好的后果基本上有两个:
1、第一种情况,设计的时候有问题,把太多的功能接口包含进来,那其中必然有一部分功能永远用不到,也就自然违反了接口隔离原则。
  我们看一下实例:
   场景介绍: 一对小情侣,一天女生给男生打电话,告诉他车被追尾了,哭的梨花带雨。小男生情商高,哄小女生说 不要紧,明天给你买辆坦克,就不怕追尾了。(前提是小女生不能开炮,只能开~~~~)
 
 
   第一版的实现=》小女生只会开汽车,不会开别的
  
#region 车辆接口和实现

    interface IVehicle
    {
        void Run();
    }

    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Car is Running");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Truck is Running");
        }
    }

    #endregion

  驾驶员类:

class Driver
    {
        private IVehicle _vehicle;
        public Driver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public void Drive()
        {
            _vehicle.Run();
        }
    }

服务调用方:

var driver = new Driver(new Car());//开汽车
            driver = new Driver(new Truck());//开卡车
            driver.Drive();

            //这时候你会发现,如果小女生想要开坦克的话,目前是满足不了的
            //因为Driver构造参数传递的是IVehicle接口,不是ITank接口
            //如果想要满足小女生开坦克上街的愿望,就必须改造Driver,传递ITank接口,请看下一个例子

            Console.ReadKey();

  第二版的实现=》小女生能开坦克,但是却不能开汽车了

      

class Driver
    {
        private ITank _tank;
        public Driver(ITank tank)
        {
            _tank = tank;
        }
        public void Drive()
        {
            _tank.Run();
        }
    }
var driver = new Driver(new HeavyTank());//开坦克
            driver.Drive();

            // 这时候你会发现, 小女生能开坦克上街了,但是你又会发现,小女生现在只会开坦克了,不会开车了
            // 问题出现在哪里呢?
            // 我们把一个胖接口(ITank)传递进来,这个胖接口中有一个我们永远用不到的功能,就是fire。
            // 所以现在这个设计是违反了接口隔离原则
            // 具体改造请看下一个例子

            Console.ReadKey();

 

   第三版的实现=》符合接口隔离原则,小女生能开坦克,也能开汽车了。
#region 车辆接口和实现

    interface IVehicle
    {
        void Run();
    }

    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Car is Running");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Truck is Running");
        }
    }

    #endregion
interface IWeapon
    {
        void Fire();
    }
interface ITank:IVehicle,IWeapon
    {
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom!");
        }

        public void Run()
        {
            Console.WriteLine("Ka Ka Ka!");
        }
    }

    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom!!!!!!!!");
        }

        public void Run()
        {
            Console.WriteLine("Ka!!! Ka!!!! Ka!!!!!!");
        }
    }

驾驶员类:

class Driver
    {
        private IVehicle _vehicle;
        public Driver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public void Drive()
        {
            _vehicle.Run();
        }
    }

服务调用方:

//接口隔离的原则是 服务的调用方不会都要
            //本例子中服务的调用方的需求很简单,这是要求会run,不要求fire
            //因此原先的ITank接口中自己包含的fire和run就符合胖接口的规则,他提供了多余的接口给调用方
            //因此把ITank接口隔离开是对的
            var driver = new Driver(new HeavyTank());//开坦克
            driver.Drive();
            driver = new Driver(new Car());//开汽车
            driver.Drive();


            Console.ReadKey();

 

 第二种情况明天继续,哇哈哈~~~~~~~~~~
 

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
树莓派(Raspberry Pi):完美的家用服务器

自从树莓派发布后,所有在互联网上的网站为此激动人心的设备提供了很多有趣和具有挑战性的使用方法。虽然这些想法都很棒,但树莓派( RPi )最明显却又是最不吸引人的用处是:创建你的完美家用...

异次元
2013/11/09
6.4K
8
Javascript图元绘制库--ternlight

基于HTML CANVAS API的Javascript库,提供在HTML页面上绘制图元——如流程图的能力。 目前已支持简单的矩形图元和图元间的连线(直线、直角连线两种),拖拽图元等能力。 该javascript librar...

fancimage1
2013/02/07
6.2K
1
实时分析系统--istatd

istatd是IMVU公司工程师开发的一款优秀的实时分析系统,能够有效地收集,存储和搜索各种分析指标,类似cacti,Graphite,Zabbix等系统。实际上,istatd修改了Graphite的存储后端,重新实现了...

匿名
2013/02/07
2.9K
1
Hbase的Windows访问接口库--libhbase4win

libhbase4win是基于Thrift的Hbase的Windows访问接口库,开发工具使用VS2010,Hadoop版本为1.1.0,Hbase版本为0.94.0,thrift版本0.9.0,执行编译需要boost和thrift支持。...

张子良
2013/03/06
761
0
图形化的 IDE--LiveCode

LiveCode是一个图形化的IDE,允许用户通过拖放控件并编写代码,来创建桌面或移动应用程序(支持Windows、Mac OS、Linux、iOS和Android平台)。LiveCode受苹果HyperCard的启发,采用一种基于英...

匿名
2013/04/12
7.1K
0

没有更多内容

加载失败,请刷新页面

加载更多

React Native常用第三方组件汇总

react-native-animatable 动画 react-native-carousel 轮播 react-native-countdown 倒计时 react-native-device-info 设备信息 react-native-fileupload 文件上传 react-native-icons 图标 ......

mdoo
31分钟前
8
0
troubleshoot之:用control+break解决线程死锁问题

简介 如果我们在程序中遇到线程死锁的时候,该怎么去解决呢? 本文将会从一个实际的例子出发,一步一步的揭开java问题解决的面纱。 死锁的代码 写过java多线程程序的人应该都知道,多线程中一...

flydean
32分钟前
19
0
无法打开与身份验证代理的连接 - Could not open a connection to your authentication agent

问题: I am running into this error of: 我遇到以下错误: $ git push heroku masterWarning: Permanently added the RSA host key for IP address '50.19.85.132' to the list of known ......

法国红酒甜
48分钟前
25
0
Trivy

Trivy 是一个面向镜像的漏洞检测工具,具备如下特点: 开源 免费 易用 准确度高 CI 友好 相对于老前辈 Clair,Trivy 的使用非常直观方便,适用于更多的场景。 下面是官方出具的对比表格: 扫...

LitStone
今天
9
0
在UITableView中使用自动布局以获取动态单元格布局和可变的行高

问题: 如何在表格视图的UITableViewCell使用自动布局,以使每个单元格的内容和子视图确定行高(自身/自动),同时保持流畅的滚动性能? 解决方案: 参考一: https://stackoom.com/questio...

技术盛宴
今天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部