作者:VieLei
原文:https://blog.csdn.net/s10461/article/details/53941097

在android中我们常提起的设计模式大约有23种,利用好设计模式能够帮助我们很好的构建代码结构,也便于我们以后的维护。每次看完,看的时候总觉得很明白,但是过一段时间以后都会忘记,或只记得一些片段,又或到真正使用起来的时候才会发现一系列的问题。本系列笔记会从头记录这23种设计模式,当然一定会有不正确的地方。

本系列笔记参考了《设计模式之禅》、《Android源码设计模式解析与实战》以及huachao1001的 从Android代码中来记忆23种设计模式一文。

开始之前

在所有的设计模式之前都会先将面向对象的六大原则,大部分同学都已经很明白了,所以在这里也想记录一些不一样的东西。

单一职责原则(SRP)

一个类所承担的功能或指责必须是同一类或者相近的,不要让一个类承担过多的职责。换一句话说,一个类的职责应该单一。但是在我们的使用过程中,在大部分应用中很难做到真正意义上的指责单一,所以对于单一职责原则我是这么理解的:

接口的职责必须单一。

类的设计尽量做到只有一个原因引起类的变化,指的是设计类而不是实现类,实现类做到单一职责的话无形中会增加很多类,会使原本简单的事情变得更加复杂。

开闭原则(OCP)

一个软件实体应该对扩展开发,对修改关闭。其含义是说一个软件实体应该通过扩展实现变化,而不是通过修改内部已有的代码来实现变化。

软件实体是什么?

  • 项目或软件产品中按照一定逻辑划分的模块

  • 抽象和类

  • 方法

开闭原则指导我们,当软件需要变化时应”尽量通过”扩展的方式来修改,而不是通过变化已有代码来实现,这里说的是尽量,并不是绝对不可以修改原始类,当我们嗅到“腐化”气味时应尽量早重构。而不是通过继承等方式添加新的实现,这会导致类的膨胀及历史代码的遗留。

通常我们可以用接口或抽象类来约束一组可变化的行为。主要包含3个层次:

第一:通过接口或抽象类约束扩展,对扩展边界定义,不允许实现类出现接口或抽象类以外的public 方法。
第二:参数类型、引用变量尽量使用接口或抽象对类,而不是实现类。
第三:抽象层尽量保持稳定。
当然在实际应用过程中,往往修改源代码和扩展是同时存在的。

里氏替换原则(LSP)

有两种解释方法,有一种特别麻烦、特别绕的就不再说了。

  • 所有引用基类的地方必须能透明地使用其子类对象。

依然比较绕,通俗一点解释是这样的:只要任何有父类出现的地方(如形参),都可以替换为子类,而且替换为子类也不会产生异常和错误。对于使用者(方法)本身不需要关心到底是父类还是子类。

但是,有子类出现的地方,替换为父类就不一定可以了。

举个例子:

//窗口类public class Window(){    public void show(View child){        child.draw();    }}public abstract class View(){    public abstract void draw();    public void measure(int widht,int height){        //测量视图大小    }}public class Button extends View{    public void draw(){        //绘制按钮    }}

public class TextView extends View{    public void draw(){        //绘制文本    }}

里氏替换原则为良好的继承定义了一个规范:

  • 1、子类必须完全实现父类的方法。我们在做系统设计的时候经常定义一个接口或抽象类,然后编码实现,调用类直接传入接口或抽象类,其实这里已经使用了里氏原则。

如果子类不能全实现父类的方法,或者父类的某些方法在子类中已经发生畸变,建议断开继承关系,采用依赖、聚合、组合等关系代替。

  • 2、子类有自己的个性。即有子类出现的地方,父类未必可以。

  • 3、覆盖或实子类重载父类的方法时,传入的参数必须比父类更宽松(相同或范围大)。(否则会出现本来虚调用父类方法的地方调用了子类的方法)

  • 4、覆盖或实子类重载父类的方法时,返回的结果必须范围更小(和父类类型相同或是父类返回类型的子类)。
    依赖倒置原则(DIP)
    依赖倒置主要是实现解耦,使得高层次的模块不依赖于低层次模块的具体实现细节。怎么去理解它呢,我们需要知道几个关键点:

(1)高层模块不应该依赖底层模块(具体实现),二者都应该依赖其抽象(抽象类或接口)。模块之间的依赖通过抽象产生,实现类之间不发生直接依赖关系,依赖关系通过接口或抽象类产生。

高层模块就是调用端,底层模块就是具体实现类。

(2)抽象不应该依赖细节(废话,抽象类跟接口肯定不依赖具体的实现了)

(3)细节应该依赖于抽象(同样废话,具体实现类肯定要依赖其继承的抽象类或接口)
在我们用的Java语言中,抽象就是指接口或者抽象类,二者都是不能直接被实例化;细节就是实现类,实现接口或者继承抽象类而产生的类,就是细节。使用Java语言描述就简单了:就是各个模块之间相互传递的参数声明为抽象类型,而不是声明为具体的实现类;

依赖导致的本质是通过抽象使各个类或者模块的实现彼此独立,不相互影响,实现模块间的松耦合。

每个类(底层模块)尽量有接口和抽象类,或者接口抽象类二者皆有。
变量的声明尽量是抽象或者接口
尽量不覆盖父类的方法
里氏替换原则
一个例子:
母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。代码如下:

class Book{      public String getContent(){          return "很久很久以前有一个阿拉伯的故事……";      }  }  

class Mother{      public void narrate(Book book){          System.out.println("妈妈开始讲故事");          System.out.println(book.getContent());      }  }  

public class Client{      public static void main(String[] args){          Mother mother = new Mother();          mother.narrate(new Book());      }  }  

运行结果:妈妈开始讲故事 很久很久以前有一个阿拉伯的故事……

运行良好,假如有一天,需求变成这样:不是给书而是给一份报纸,让这位母亲讲一下报纸上的故事,报纸的代码如下:

class Newspaper{      public String getContent(){          return "林书豪38+7领导尼克斯击败湖人……";      }  }  

这位母亲却办不到,因为她居然不会读报纸上的故事,这太荒唐了,只是将书换成报纸,居然必须要修改Mother才能读。假如以后需求换成杂志呢?换成网页呢?还要不断地修改Mother,这显然不是好的设计。原因就是Mother与Book之间的耦合性太高了,必须降低他们之间的耦合度才行。

我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物:

interface IReader{      public String getContent();  }  

Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为:

class Newspaper implements IReader {      public String getContent(){          return "林书豪17+9助尼克斯击败老鹰……";      }  }  

class Book implements IReader{      public String getContent(){          return "很久很久以前有一个阿拉伯的故事……";      }  }  

class Mother{      public void narrate(IReader reader){          System.out.println("妈妈开始讲故事");          System.out.println(reader.getContent());      }  }  

public class Client{      public static void main(String[] args){          Mother mother = new Mother();          mother.narrate(new Book());          mother.narrate(new Newspaper());      }  }     

这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。这只是一个简单的例子,实际情况中,代表高层模块的Mother类将负责完成主要的业务逻辑,一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。

依赖倒置原则在Java中的表现就是:模块间通过抽象发生,实现类之间不发生直接依赖关系,其依赖关系是通过接口或者抽象类产生的。如果类与类直接依赖细节,那么就会直接耦合,那么当修改时,就会同时修改依赖者代码,这样限制了可扩展性。

接口隔离原则(ISP)
关于接口有一点要说明:类也是接口

有两种定义方法:一种为类不应该依赖它不需要的接口;另一种为类之间的依赖关系应该建立在最小的接口上。接口隔离的原则是将非常庞大、臃肿的接口分割成更小更具体的接口。

有的时候会感觉单一职责和接口隔离隔离原则很像,单一职责更关注的是功能的单一,是业务层次上的划分。而接口隔离原则更关心的是接口的数量要少。

比如说一个接口有一组10个功能,提供给若干个模块使用,每个模块按照按照不同的权限只能使用接口中的一部分功能。按照单一职责原则是允许的,但是按照接口隔离原则是不允许的,接口隔离原则要求:”尽量使用多个专用接口”,意思为有几个模块就提供几个接口,而不是建立一个庞大的接口供所有模块使用。

接口设计时有限度的,当然也不要分了隔离接口而将全部接口都细化,这样就变为过度设计了

最佳实践:

  • 一个接口只服务于一个模块或业务流程

  • 压缩接口对外提供的public方法

迪米特原则(LOD)

一个对象应该对一个被调用的类(被耦合)有最少的了解。调用者只需要知道它需要调用的方法即可。类与类之间的关系越密切,当一个类发生改变时,对另一个类影响也越大。

迪米特原则包含的四层含义:

  • 只和朋友交流:每个类必然会和其他类有耦合关系,两个对象间的耦合就成为朋友关系(聚合、组合、依赖等)。朋友类得定义是这样的:出现在成员变量、方法的输入、输出参数中的称为成员朋友类,而出现在方法体内部的类不属于朋友类。

  • 朋友之间也是有距离的:不要对外公布太多的public方法和非静态的public变量,尽量内敛。

迪米特原则的核心观念是:解耦。即:高内聚、低耦合。

最后

  • 单一职责原则 (SRP)

  • 开闭原则 (OCP)

  • 里氏替换原则 (LSP)

  • 迪米特原则 (LOD)

  • 接口隔离原则 (ISP)

  • 依赖倒置原则 (DIP)
    至此设计模式的6大基础原则几经全部介绍完毕,将6大原则的首字母组合起来,就是SOLID(稳定的)。

不是说按照一定的设计模式来设计程序就能应对各种场景,或不对代码结构做任何修改。只是我们在进行程序设计的时候尽量遵循这6大原则。

长按关注,更多精彩

看完,有收获就点个“好看”鸭

↓↓↓↓

接口隔离原则_设计模式六大原则相关推荐

  1. python里氏替换原则_设计模式六大原则之里氏替换原则

    这是设计模式6 大原则系列的第二篇文章,附上前一篇文章地址:设计模式六大原则之单一职责原则.本文主要讲解设计模式的里氏替换原则. 肯定有不少人跟我刚看到这项原则的时候一样,对这个原则的名字充满疑惑.其 ...

  2. java设计模式六大原则之场景应用分析

    面对项目中如此众多的设计模式,我们有时候无法 下手.在强大的设计框架也终脱离不了23种设计模式,6大原则.我们只要把内功修炼好,掌握其精髓也离我们不远了... 目录: 设计模式六大原则(1):单一职责 ...

  3. 软件设计模式六大原则

    设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计模式六大 ...

  4. android之设计模式六大原则

    设计模式面向对象软件设计开发模式 目录(?)[-] 设计模式六大原则1单一职责原则 设计模式六大原则2里氏替换原则 设计模式六大原则3依赖倒置原则 设计模式六大原则4接口隔离原则 设计模式六大原则5迪 ...

  5. 设计模式六大原则(五)接口隔离原则

    设计模式六大原则 定义:简称ISP.客户端不应该依赖它不需要的接口:一个类对另一个类的依赖应该建立在最小的接口上. 举例子: 给出指定食材(西红柿.黄瓜.芹菜),冷热菜师傅要根据自己的需求不同,对食材 ...

  6. 第一部分:设计模式六大原则解读——什么是接口隔离

    设计模式六大原则解读--什么是接口隔离 author:陈镇坤27 创建日期:2022年1月31日 文章目录 设计模式六大原则解读--什么是接口隔离 一.接口隔离 1.接口隔离的定义 2.接口隔离的目的 ...

  7. python三大特征六大原则_设计模式-来玩魔王的咚!-51CTO博客

    每一个设计模式系统的命名.解释和评价了面向对象系统中一个重要的和重复出现的设计.这里面向对象划重点,意思是所有的设计模式都是针对面向对象的提出的. 设计模式的4个基本要素: 模式名称 问题 解决方案 ...

  8. PHP 设计模式六大原则

    http://www.cnblogs.com/yujon/p/5536118.html 设计模式六大原则(1):单一职责原则 不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责 设计模 ...

  9. Java 设计模式六大原则

    Java 设计模式六大原则 单一职责原则 定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 问题由来:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而 ...

最新文章

  1. sqoop mysql where_Sqoop基本语法简介
  2. 在Asp.net core 项目中操作Mysql数据库
  3. 3Com发布新MSR路由器 为企业提供视频播客支持
  4. python将dataframe写入csv_Pandas dataframe数据写入文件和数据库
  5. 剑指offer之求两个数之和(不能使用四则运算)
  6. aws es方案_AWS Elasticsearch后模式
  7. 使用Apache Drill REST API通过Node构建ASCII仪表板
  8. go连接mysql数据库
  9. 感觉又学到了不少,在这里写下来,但也有一个问题,不知道是为甚吗?
  10. 歪枣网数据库设计-千万级别海量数据查询效率优化
  11. 今天最好的生日礼物就是重新找到目标
  12. springboot Hello World探究
  13. jmeter获取毫秒时间戳
  14. MVC模式在Java web 应用程序的实现
  15. html中多个div分开排列,CSS+DIV设计实例:多个DIV排列时居中
  16. Python核心编程第三版
  17. 那些年,我开发过的软件
  18. 色粉画的发展历程与西方艺术中的色粉画
  19. js 相对路径转为绝对路径
  20. 美图秀秀网页版新功能上线 新增磨皮祛痘

热门文章

  1. ue4 无限地图_RPG游戏开发日志13:无限地图的实现
  2. java 内部类 加载_举例讲解Java的内部类与类的加载器
  3. ant 改变表格数据_学不会这几个操作,面试时千万别说自己精通数据分析
  4. 使用命令创建mysql_用命令创建MySQL数据库
  5. numpy pytorch 接口对应_用树莓派4b构建深度学习应用(四)PyTorch篇
  6. Xshell连接服务器出现(To escape to local shell, press 'Ctrl+Alt+]'.)问题、xshell终端中文乱码完全解决方法
  7. java数组split_js数组接受split(java split)
  8. visualstudio开始调试不执行_攻击者是如何滥用msvsmon和Windows远程调试器的
  9. wpf 为html 变量赋值_JavaScript 变量
  10. mybatisplus 操作另一个数据库的数据_c#连接sql数据库以及操作数据库