PHP面向对象五大原则之接口隔离原则(ISP)详解


Posted in PHP onApril 04, 2018

本文实例讲述了PHP面向对象五大原则之接口隔离原则(ISP)。分享给大家供大家参考,具体如下:

设计应用程序的时候,如果一个模块包含多个子模块,那么我们应该小心对模块做出抽象。设想该模块由一个类实现,我们可以把系统抽象成一个接口。但是要添加一个新的模块扩展程序时,如果要添加的模块只包含原系统中的一些子模块,那么系统就会强迫我们实现接口中的所有方法,并且清寒要编写一些哑方法。这样的接口被称为肚胖接口或者被污染的接口,使用这样的接口将会给系统引入一些不当的行为,这些不当的行为可能导致不正确的结果,也可能导入资源浪费。

1.接口隔离

接口隔离原则(Interface Segregation Principle, ISP)表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口替代它,每个接口服务于一个子模块。简单地说,就是使用多个专门的接口比使用单个接口要好很多。

ISP的主要观点如下:

1)一个类对另外一个类的依赖性应当是建立在最小的接口上的。

ISP可以达到不强迫客户(接口的使用方法)依赖于他们不用的方法,接口的实现类应该只呈现为单一职责的角色(遵循SRP原则)

ISP还可以降低客户之间的相互影响---当某个客户要求提供新的职责(需要变化)而迫使接口发生改变时,影响到其他客户程序的可能性最小。

2)客户端程序不应该依赖它不需要的接口方法(功能)。

客户端程序就应该依赖于它不需要的接口方法(功能),那依赖于什么?依赖它所需要的接口。客户端需要什么接口就是提供什么接口,把不需要的接口剔除,这就要求对接口进行细化,保证其纯洁性。

比如在继承时,由于子类将继承父类中的所有可用方法;而父类中的某些方法,在子类中可能并不需要。例如,普通员工和经理都继承自雇员这个接口,员工需要每天写工作日志,而经理不需要。因此不能用工作日志来卡经理,也就是经理不应该依赖于提交工作日志这个方法。

可以看出,ISP和SRP在概念上是有一定交叉的。事实上,很多设计模式在概念上都有交叉,甚至你很难判断一段代码属于哪一种设计模式。

ISP强调的是接口对客户端的承诺越少越好,并且要做到专一。当某个客户程序的要求发生变化,而迫使接口发生改变时,影响到其他客户程序的可能性小。这实际上就是接口污染的问题。

2.对接口的污染

过于臃肿的接口设计是对接口的污染。所谓的接口污染就是为接口添加不必要的职责,如果开发人员在接口中增加一个新功能的目的只是减少接口实现类的数目,则此设计将导致接口被不断地“污染”并“变胖”。

“接口隔离”其实就是定制化服务设计的原则。使用接口的多重继承实现对不同的接口的组合,从而对外提供组合功能---达到“按需提供服务”。

接口即要拆,但也不能拆得太细,这就得有个标准,这就是高内聚。接口应该具备一些基本的功能,能独一完成一个基本的任务。

在实际应用中,会遇到如下问题:比如,我需要一个能适配多种类型数据库的DAO实现,那么首先应实现一个数据库操作的接口,其中规定一些数据库操作的基本方法,比如连接数据库、增删改查、关闭数据库等。这是一个最少功能的接口。对于一些MySQL中特有的而其他数据库里并不存在的或性质不同的方法,如PHP里可能用到的MySQL的pconnect方法,其他数据库里并不存在和这个方法相同的概念,这个方法也就不应该出现在这个基本的接口里,那这个基本的接口应该有哪些基本的方法呢?PDO已经告诉你了。

PDO是一个抽象的数据库接口层,它告诉我们一个基本的数据库操作接口应该实现哪些基本的方法。接口是一个高层次的抽象,所以接口里的方法都应该是通用的、基本的、不易变化的。

还有一个问题,那些特有的方法应该怎么实现?根据ISP原则,这些方法可以在别一个接口中存在,让这个“异类”同时实现这两个接口。

对于接口的污染,可以考虑这两条处理方式:

利用委托分离接口。

利用多继承分离接口。

委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理,如策略模式、代理模式等中都应用到了委托的概念。

再来看一下实例说明

你是否遇到过非常“胖”的接口呢?

举个例子来说吧:有一个跟动物有关的接口,代码如下:

<?php
interface Animal{
  public function walk();
  public function speak();
}

狗是这个接口的一个具体实现:

<?php
require_once "animal.php";
class Dog implements Animal{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
}

ok,现在我们想创建一个鱼类,它会游泳,怎么办呢?我们必须要修改接口,还会影响到dog类的实现,而fish也需要实现walk和speak方法,如下代码所示:

Animal接口类:

<?php
interface Animal{
  public function walk();
  public function speak();
  public function swim();
}

dog类:

<?php
require_once "animal.php";
class Dog implements Animal{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
  public function swim(){
  }
}

fish类:

<?php
require_once "animal.php";
class Fish implements Animal{
  public function walk(){
  }
  public function speak(){
  }
  public function swim(){
    echo "fish can swim";
  }
}

这时Animal接口类就呈现出了”胖“接口的特征了。所谓胖接口其实就是接口中定义了不是所有实现类都需要的方法,就像Animal接口类,有些动物是不会游泳的,有些动物是不会行走的,还有些动物是不会飞的。如果将这些方法都写在一个Animal接口类中,那么后期的扩展和维护简直就是一场灾难。

那么,怎么解决以上问题呢?

很简单,接口细化即可,将Animal接口类拆分成三个接口类:

animalCanWalk接口类:

<?php
interface animalCanSpeak{
  public function speak();
}

AnimalCanSwim接口类:

<?php
interface AnimalCanSwim{
  public function swim();
}

animalCanSpeak接口类:

<?php
interface animalCanSpeak{
  public function speak();
}

定义好这几个接口类之后,dog和fish的实现就容易多了,

<?php
require_once "animalCanSpeak.php";
require_once "animalCanWalk.php";
class Dog implements animalCanSpeak,animalCanWalk{
  public function walk(){
    echo "dogs can walk";
  }
  public function speak(){
    echo "dogs can speak";
  }
}
<?php
require_once "animalCanSwim.php";
class Fish implements AnimalCanSwim{
  public function swim(){
    echo "fish can swim";
  }
}

总结一下:

接口隔离原则(Interface  Segregation Principle, ISP)的概念:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP中实现进程间通讯
Oct 09 PHP
兼容PHP5的PHP目录管理函数库
Jul 10 PHP
php防攻击代码升级版
Dec 29 PHP
php数组函数序列之krsort()- 对数组的元素键名进行降序排序,保持索引关系
Nov 02 PHP
php读取mysql中文数据出现乱码的解决方法
Aug 16 PHP
19个Android常用工具类汇总
Dec 30 PHP
PHP实现抓取Google IP并自动修改hosts文件
Feb 12 PHP
PHP生成随机密码方法汇总
Aug 27 PHP
Zend Framework常用校验器详解
Dec 09 PHP
thinkPHP5.0框架模块设计详解
Mar 18 PHP
完美解决在ThinkPHP控制器中命名空间的问题
May 05 PHP
laravel 多图上传及图片的存储例子
Oct 14 PHP
PHP面向对象五大原则之开放-封闭原则(OCP)详解
Apr 04 #PHP
PHP面向对象五大原则之单一职责原则(SRP)详解
Apr 04 #PHP
PHP基于面向对象实现的留言本功能实例
Apr 04 #PHP
PHP设计模式之工厂模式定义与用法详解
Apr 03 #PHP
PHP设计模式之原型模式定义与用法详解
Apr 03 #PHP
thinkPHP框架自动填充原理与用法分析
Apr 03 #PHP
PHP设计模式之适配器模式定义与用法详解
Apr 03 #PHP
You might like
PHP 解决utf-8和gb2312编码转换问题
2010/03/18 PHP
关于PHP结束标签的使用细节探讨及联想
2013/03/04 PHP
php计算给定日期所在周的开始日期和结束日期示例
2017/02/06 PHP
[原创]用javascript实现检测指定目录是否存在的方法
2008/01/12 Javascript
JS设置获取cookies的方法
2014/01/26 Javascript
jQuery实现单击按钮遮罩弹出对话框(仿天猫的删除对话框)
2014/04/10 Javascript
jQuery消息提示框插件Tipso
2015/05/04 Javascript
浅谈angularJS 作用域
2015/07/05 Javascript
js简单实现表单中点击按钮动态增加输入框数量的方法
2015/08/18 Javascript
jQuery实现控制文字内容溢出用省略号(…)表示的方法
2016/02/26 Javascript
JavaScript中的this使用详解
2016/07/27 Javascript
Bootstrap 3的box-sizing样式导致UEditor控件的图片无法正常缩放的解决方案
2016/09/15 Javascript
JS判断来路是否是百度等搜索索引进行弹窗或自动跳转的实现代码
2016/10/09 Javascript
jquery判断页面网址是否有效的两种方法
2016/12/11 Javascript
JS库之Three.js 简易入门教程(详解之一)
2017/09/13 Javascript
基于vue实现图片验证码倒计时60s功能
2019/12/10 Javascript
解决elementUI 切换tab后 el_table 固定列下方多了一条线问题
2020/07/19 Javascript
python实现bitmap数据结构详解
2014/02/17 Python
DJANGO-ALLAUTH社交用户系统的安装配置
2014/11/18 Python
网站渗透常用Python小脚本查询同ip网站
2017/05/08 Python
基于Django的python验证码(实例讲解)
2017/10/23 Python
Python实现压缩文件夹与解压缩zip文件的方法
2018/09/01 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
用Python中的turtle模块画图两只小羊方法
2019/04/09 Python
python sklearn包——混淆矩阵、分类报告等自动生成方式
2020/02/28 Python
keras训练曲线,混淆矩阵,CNN层输出可视化实例
2020/06/15 Python
Python 实现简单的客户端认证
2020/07/29 Python
CSS3等相关属性制作分页导航实现代码
2012/12/24 HTML / CSS
顶丰TOPPIK台湾官网:增发纤维假发,告别秃发困扰
2018/06/13 全球购物
有关打架的检讨书
2014/01/25 职场文书
煤矿机修工岗位职责
2014/02/07 职场文书
市场营销方案范文
2014/03/11 职场文书
应聘编辑自荐信范文
2014/03/12 职场文书
小英雄雨来观后感
2015/06/09 职场文书
煤矿安全生产工作总结
2015/08/13 职场文书
未来,这5大方向都很适合创业
2019/07/22 职场文书