昨天我看了单一职责原则和开闭原则,今天我们再来看里式替换原则和依赖倒置原则,千万别小看这些设计原则,他在设计模式中会有很多体现,所以理解好设计原则之后,那么设计模式,也会让你更加的好理解一点。

前言

在面向对象的软件设计中,只有尽量降低各个模块之间的耦合度,才能提高代码的复用率,系统的可维护性、可扩展性才能提高。面向对象的软件设计中,有23种经典的设计模式,是一套前人代码设计经验的总结,如果把设计模式比作武功招式,那么设计原则就好比是内功心法。常用的设计原则有七个,下文将具体介绍。

设计原则简介

  • 单一职责原则:专注降低类的复杂度,实现类要职责单一;
  • 开放关闭原则:所有面向对象原则的核心,设计要对扩展开发,对修改关闭;
  • 里式替换原则:实现开放关闭原则的重要方式之一,设计不要破坏继承关系;
  • 依赖倒置原则:系统抽象化的具体实现,要求面向接口编程,是面向对象设计的主要实现机制之一;
  • 接口隔离原则:要求接口的方法尽量少,接口尽量细化;
  • 迪米特法则:降低系统的耦合度,使一个模块的修改尽量少的影响其他模块,扩展会相对容易;
  • 组合复用原则:在软件设计中,尽量使用组合/聚合而不是继承达到代码复用的目的。

这些设计原则并不说我们一定要遵循他们来进行设计,而是根据我们的实际情况去怎么去选择使用他们,来让我们的程序做的更加的完善。

里式替换原则

定义:

如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2 时,程序P的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

换句话来说,一个软件实体如果使用一个基类的话,那么一定适用于其子类,而且它根本不会察觉出基类对象和子类对象的区别。

比如说,假设有两个类,一个是Base类,另一个是Derived类,并且Derived类是Base的子类,那么一个方法如果可以接受一个基类对象b的话:method(Base b) ,那么它必然可以接受一个子类对象d,可以有 method1(d)

里式替换原则是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不会受到影响的时候,基类才能真正被复用,而衍生类也才能够在基类的基础上增加新的行为。

我们通过一个例子来理解一下:

《西游记》中,美猴王下地府桥段,个位应该有印象把,到达阎王殿之后,拿到生死簿,把生死簿上所有的包括自己,还有其他的猕猴,所有的猴子猴算都给划了,这也是导致之后真假美猴王桥段的前序。

画个图理解

很显然,地府管理一切生灵的生死的方法都是通过类来进行区分的,比如孙悟空就是石猴,之后出现的那个六耳猕猴就是猕猴,但是他们都是属于同一个类,猴类,就像下图中。

因此,孙悟空把猴类中有姓名的都从生死簿勾掉之后,显然是因为勾魂小鬼们并不区分石猴类与猕猴类,就像下图:

换句话来说,只要是猴类适用的,猕猴和石猴都适用,这其实就是里式替换原则。

这是第一种解释,还有第二个更加通俗易懂的解释:所有引用基类的地方必须能透明地使用其子类的对象。

第二种定义比较通俗,容易理解:只要有父类出现的地方,都可以用子类来替代,而且不会出现任何错误和异常。但是反过来则不行,有子类出现的地方,不能用其父类替代。

实例代码:

public class TestA {    public void fun(int a,int b){        System.out.println(a+"+"+b+"="+(a+b));    }    public static void main(String[] args) {        System.out.println("父类的运行结果");        TestA a=new TestA();        a.fun(1,2);        //父类存在的地方,可以用子类替代        //子类B替代父类A        System.out.println("子类替代父类后的运行结果");        TestB b=new TestB();        b.fun(1,2);    }}class TestB extends TestA{    @Override    public void fun(int a, int b) {        System.out.println(a+"-"+b+"="+(a-b));    }}

大家肯定也都能猜出来结果是什么样子的,

父类的运行结果1+2=3子类替代父类后的运行结果1-2=-1Process finished with exit code 0

我们想要的结果是“1+2=3”。可以看到,方法重写后结果就不是了我们想要的结果了,也就是这个程序中子类B不能替代父类A。这违反了里氏替换原则原则,从而给程序造成了错误。

子类中可以增加自己特有的方法

这个很容易理解,子类继承了父类,拥有了父类和方法,同时还可以定义自己有,而父类没有的方法。这是在继承父类方法的基础上进行功能的扩展,符合里氏替换原则。

public class TestA {    public void fun(int a,int b){        System.out.println(a+"+"+b+"="+(a+b));    }    public static void main(String[] args) {        System.out.println("父类的运行结果");        TestA a=new TestA();        a.fun(1,2);        //父类存在的地方,可以用子类替代        //子类B替代父类A        System.out.println("子类替代父类后的运行结果");        TestB b=new TestB();        b.fun(1,2);        b.newFun();    }}class TestB extends TestA{    public void newFun(){        System.out.println("这是子类的新方法...");    }}

这次运行出来的代码结果就是我们意料中的内容了

父类的运行结果1+2=3子类替代父类后的运行结果1+2=3这是子类的新方法...Process finished with exit code 0

JAVA语言对里式替换原则支持的局限:

JAVA编译器的检查是有局限性的,为什么呢?举个例子来说,描述一个物体大小的量有精度和准确度两种属性。所谓的精度,就是这个量的有效数字有多少位;而所谓的精准度,是这个量与真实的物体大小相符合到什么程度。

一个量可以有很高的精度,但是却无法与真实物体的情况相吻合,JAVA语言编译器能够检查的,仅仅是相当于精度的属性而已,它没有办法去检查这个量与真实物体的差距。

换一句话来说,JAVA编译器不能检查一个系统在实现和商业逻辑上是否满足里式替换原则。

而里式替换原则在设计模式中也有体现,请关注我们的知识星球,链接在文末,我们将每周更新一篇关于设计模式的文章。

依赖倒置原则

如果说实现开闭原则的关键事抽象化,是面向对象设计的目标的话,依赖倒置原则就是这个面向对象设计的主要机制。

定义:

抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

为什么要实现倒置?这也是我们看这个定义的时候产生的一些问题,那么我们就来说说。

简单的来说,传统的过程性系统的设计办法倾向于使高层次的模块依赖于低层次的模块,抽象层依赖于具体层次,倒置原则是要把这个错误的依赖关系倒转过来,这就是依赖倒置原则的由来。也是为什么要进行依赖倒置。

依赖倒置原则的实现方法

依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则:

  • 每个类尽量提供接口或抽象类,或者两者都具备。
  • 变量的声明类型尽量是接口或者是抽象类。
  • 任何类都不应该从具体类派生。
  • 使用继承时尽量遵循里氏替换原则。

下面我们通过一些代码实例(商品售卖)来进行理解:

    class BeijingShop implements Shop{        public String sell(){            return "北京商店售卖:北京烤鸭,稻香村月饼";        }    }        class ShanDongShop implements  Shop{        @Override        public String sell() {            return "山东商店售卖:德州扒鸡,烟台苹果";        }    }    //如果说顾客去购买商品class Customer{    public void shopping(ShanDongShop shop)    {        //购物        System.out.println(shop.sell());    }}//这是在山东商店购买,如果说是在北京商店购买就会这样class Customer{    public void shopping(BeijingShop shop)    {        //购物        System.out.println(shop.sell());    }}

这也是这种设计的存在缺陷,顾客每更换一家商店,都要修改一次代码,这明显违背了开闭原则。存在以上缺点的原因是:顾客类设计时同具体的商店类绑定了,这违背了依赖倒置原则。解决方式我们可以定义一个共同的接口Shop,就可以这样了

public class TestSale {    public static void main(String[] args) {        Customer c = new Customer();        System.out.println("---顾客购买商品如下---");        c.shopping(new ShanDongShop());        c.shopping(new BeijingShop());    }}interface Shop{    //售卖方法    public String sell();}class BeijingShop implements Shop{    public String sell(){        return "北京商店售卖:北京烤鸭,稻香村月饼";    }}class ShanDongShop implements  Shop{    @Override    public String sell() {        return "山东商店售卖:德州扒鸡,烟台苹果";    }}class Customer{    public void shopping(Shop shop)    {        System.out.println(shop.sell());//购物    }}

程序运行结果

---顾客购买商品如下---山东商店售卖:德州扒鸡,烟台苹果北京商店售卖:北京烤鸭,稻香村月饼Process finished with exit code 0

这样,不管顾客类 Customer 访问什么商店,或者增加新的商店,都不需要修改原有代码了,

依赖倒置原则是OO设计的核心原则,设计模式的研究和应用是以依赖导致原则为知道原则的,在知识星球中的设计模式中我们将会一一给大家体现。

依赖倒置原则_面向对象的设计原则你不要了解一下么?相关推荐

  1. 面向对象设计原则_面向对象的设计原则

    面向对象设计原则 Programming is fun until you have to incorporate a new requirement that changes the whole d ...

  2. wordvba编程代码大全_面向对象、设计原则、设计模式、编程规范、重构

    面向对象.设计原则.设计模式.编程规范.重构 面向对象 主流的三个编程风格有:面向对象,面向过程,函数式编程. 面向对象是最主流的风格,面向对象具有丰富的特性(封装,抽象,继承,多态). 面向对象 面 ...

  3. 设计数据库原则4个原则_四个设计原则

    设计数据库原则4个原则 As you progress in CSS, there are four important design principles that need to be kept ...

  4. C++设计模式的设计原则(面向对象八大设计原则)

    面向对象设计八大设计原则 一.温故面向对象 二.八大设计原则 三.以史为鉴    先掌握八大设计原则,再详细看23种设计模式(

  5. 【设计原则】面向对象的设计原则(六原则一法则)

    (一)单一职责原则:一个类只做它该做的事情. 单一职责想表达的就是"高内聚",所谓高内聚就是一个代码模块只完成一项功能,在面向对象中,如果只让一个类完成它该做的事,而不涉及与它无关 ...

  6. 带你了解面向对象的设计原则

    ##一 摘要 今天晚上给大家介绍一下面向对象的设计原则,为什么要介绍这个呢,原因很简单,大家平时所接触的语言,无论是object-C,C++,JavaScrpt,C#等都是属于面向对象语言,既然是面向 ...

  7. 面向对象的设计原则最终篇

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 关于面向对象的设计原则我之前已经解释过四种了,分别是单一职责原则,开放关闭原则,里式替换原则, ...

  8. 设计模式:面向对象的设计原则下(ISP、DIP、KISS、YAGNI、DRY、LOD)

    本文继续来介绍接口隔离原则(ISP)和依赖倒置原则(DIP),这两个原则都和接口和继承有关.文章最后会简单介绍几个除了 SOLID 原则之外的原则. 接口隔离原则(ISP) 提起接口,开发人员的第一反 ...

  9. Java 面向对象的设计原则

    一. 1.面向对象思想的核心: 封装.继承.多态.   2.面向对象编程的追求: 高内聚低耦合的解决方案: 代码的模块化设计: 3.什么是设计模式: 针对反复出现的问题的经典解决方案,是对特定条件下( ...

最新文章

  1. HotSpot虚拟机对象的创建过程
  2. ASP.NET的MVC中使用Session做身份验证(附代码下载)
  3. 让女朋友能懂的网络技术篇之动态代理
  4. 读后感《我回阿里的29个月》
  5. php 登陆信息 传递,PHP传递POST信息
  6. CVPR 2020 算法竞赛大盘点
  7. 95-190-040-源码-window-Session Window
  8. 常见linux服务器系统异常问题
  9. 开源监控系统------Zabbix
  10. 白话阿里巴巴Java开发手册高级篇
  11. 排序(二分插入排序)
  12. 房屋租赁管理系统mysql(含论文)
  13. 令牌环网Token Ring协议
  14. 《现代控制系统》第四章——反馈控制系统特性 4.1 介绍
  15. c++高级编程学习笔记7
  16. IE下使用VLC网页播放视频Demo
  17. [导入]干掉Google Base? 微软欲推Fremont服务
  18. 有没有ai绘画教程?什么软件能实现ai绘画?
  19. .Net 微信开发与微信支付
  20. 笔记本计算机屏幕亮度暗,笔记本屏幕暗,详细教您怎么解决

热门文章

  1. 新生代的他们,正在续写“黑客”传奇
  2. 任正非回应退休传闻;董明珠谈直播首秀“失败”;Wine 5.7 发布​| 极客头条...
  3. 云原生就一定安全吗?
  4. 超 6 万的微软工程师是如何进行代码审查的?| CSDN 博文精选
  5. uni-app 2.2 发布,大幅度优化 H5 端性能体验 | 技术头条
  6. 这位程序员就这样被征服了......
  7. 打败 Python、JS、C# 成最受欢迎编程语言,是时候掌握 Rust 了吗?
  8. Google,一切皆为 AI!
  9. mysql数据库表无法显示_【MySQL8.0.18】IDEA 连接数据库无法显示数据表
  10. Spring的XML解析原理,java接口流程图