前言

前面已经明白了UML是什么,UML该在哪里用
接下来开始真正接触设计模式的思想:六大原则

目录

  1. 六大原则(七大原则)
  2. 开闭原则
    2.1. 开闭原则的作用
    2.2. 开闭原则的案例
  3. 里氏替换原则
    3.1. 里氏替换原则的作用
    3.2. 里氏替换原则的案例
  4. 依赖倒置原则
    4.1. 依赖倒置的作用
    4.2. 依赖倒置的案例
  5. 单一职责原则
    5.1. 单一职责原则优点
    5.2. 单一职责原则案例
  6. 接口隔离原则
    6.1. 接口隔离原则的优点
    6.2. 接口隔离原则的案例
  7. 迪米特法则
    7.1. 迪米特法则的优点
    7.2. 迪米特法则案例
  8. 合成复用原则
    8.1. 合成复用原则的优点
    8.2. 合成复用原则案例
  9. 总结

六大原则

实际是七大原则,几种无所谓,都是为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,都是面向对象原则

分别是:开闭原则、里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则、合成复用原则

开闭原则

开闭原则(Open Closed Principle,OCP):软件实体应当对扩展开放,对修改关闭

软件实体包括 :项目中划分出的模块,类与接口, 方法

意思是:当应用软件需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,扩展模块功能,使其实现新的需求(Java中的抽象、封装)

开闭原则的作用

开闭原则是面对对象的可复用设计的第一块基石,是最重要的面向对象设计原则,使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性

作用:

  1. 对软件测试的影响
    软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。
  2. 可以提高代码的可复用性
    粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。
  3. 可以提高软件的可维护性
    遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。

在软件不断升级维护过程中,如果改动软件实体的源代码,可能会引入错误造成需要重构软件,开闭原则就是指导我们不要动用源代码,通过扩展来完成新的需求

开闭原则的案例

Java中可以通过抽象、封装来实现开闭原则
例:一个简单的Car工厂

package com.company.DesignPatterns;abstract class CarFactory {String carType;abstract void produce();
}class BMW extends CarFactory{@Overridevoid produce() {System.out.println("生产宝马中:"+carType+"生产成功");}
}class Productor{public static void main(String [] args){BMW bmw=new BMW();bmw.carType="宝马";bmw.produce();}
}

当我们有新需求:生产AE86,就不需要动用软件实体的源代码,只需扩展一个类

class AE extends CarFactory{@Overridevoid produce() {System.out.println("生产AE86:"+carType+"生产成功");}
}

开闭原则是面向对象的最重要的原则,提升了代码的可复用性和可维护性

里氏替换原则

里氏替换原则(Liskov Substitution Principle,LSP)主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。
里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范

里氏替换原则的作用

  • 里氏替换原则是实现开闭原则的重要方式之一。
  • 它克服了继承中重写父类造成的可复用性变差的缺点。
  • 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。

里氏替换原则的案例

里氏替换原则明显就是定义了继承的原则:子类可以扩展父类的功能,但不能改变父类原有的功能,就是不能重写功能

上面的例子父类是抽象类还好,不会碰到这个问题,如果是普通父类

有一个著名的案例:几维鸟不是鸟

public class LSPtest
{public static void main(String[] args){Bird bird1=new Swallow();Bird bird2=new BrownKiwi();bird1.setSpeed(120);bird2.setSpeed(120);System.out.println("如果飞行300公里:");try{System.out.println("燕子将飞行"+bird1.getFlyTime(300)+"小时.");System.out.println("几维鸟将飞行"+bird2.getFlyTime(300)+"小时。");}catch(Exception err){System.out.println("发生错误了!");}}
}
//鸟类
class Bird
{double flySpeed;public void setSpeed(double speed){flySpeed=speed;}public double getFlyTime(double distance){return(distance/flySpeed);}
}
//燕子类
class Swallow extends Bird{}
//几维鸟类
class BrownKiwi extends Bird
{public void setSpeed(double speed){flySpeed=0;}
}

几维鸟子类对父类方法进行了重写,给原系统引进了错误

依赖倒置原则

依赖倒置原则(Dependence Inversion Principle,DIP)的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象

核心思想是:要面向接口编程,不要面向实现编程

就是使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成

这让我想起来Spring的核心思想:依赖注入、控制反转

依赖倒置的作用

  • 依赖倒置原则可以降低类间的耦合性。
  • 依赖倒置原则可以提高系统的稳定性。
  • 依赖倒置原则可以减少并行开发引起的风险。
  • 依赖倒置原则可以提高代码的可读性和可维护性

依赖倒置的案例

高耦合:

class Customer
{public void shopping(Shop shop){//购物System.out.println(shop.sell());}
}

对于一个购物类,每次购物都需要不同的Shop实例,这违反了开闭原则

依赖倒置:

package com.company.DesignPatterns;class Customer
{public void shopping(ShopType shopType){shopType.toShop();}
}
interface ShopType{public void toShop();
}class FoodShop implements ShopType{@Overridepublic void toShop() {System.out.println("前往食品店");}
}
class ClothesShop implements ShopType{@Overridepublic void toShop() {System.out.println("前往服装店");}
}class Test{public static void main(String[] args){Customer customer=new Customer();customer.shopping(new FoodShop());customer.shopping(new ClothesShop());}
}

依赖倒置之后,我们再也不需要改变Customer类的方法,只需在需要使用时注入ShopType类就完成

单一职责原则

单一职责原则(Single Responsibility Principle,SRP)规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分

就是类只能承担一个职责,多个职责会造成:

  • 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力

  • 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费

单一职责原则优点

单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点。

  • 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多
  • 提高类的可读性。复杂性降低,自然其可读性会提高
  • 提高系统的可维护性。可读性提高,那自然更容易维护了
  • 变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响

单一职责原则案例

对学生的工作有两个职责:生活辅导、学业指导,这两个职责分给辅导员和学业导师去完成,即单一职责原则(这里的职责看具体分类)

接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法

即客户端不应该被迫依赖与它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口

接口隔离与单一职责有一定的相似:都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想

两者的区别:

  • 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离

  • 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建

接口隔离原则的优点

接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 5 个优点。

  • 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性

  • 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性

  • 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险

  • 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义

  • 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码

接口隔离原则的案例

接口隔离就是提供角色需要的方法,屏蔽不需要的方法
一个接口代表一个角色,不应当将不同的角色都交给一个接口

例:吃早餐分为吃、喝
接口隔离原则就是吃早餐要分成吃接口和喝接口
吃接口只负责吃各种东西
喝接口只负责喝各种东西

package com.company.DesignPatterns;interface Drink{public void drink();
}
interface Eat{public void eat();
}
class DrinkM implements Drink{@Overridepublic void drink() {System.out.println("正在喝牛奶!");}
}
class DrinkW implements Drink{@Overridepublic void drink() {System.out.println("正在喝水!");}
}class EatB implements Eat{@Overridepublic void eat() {System.out.println("正在吃面包!");}
}
class EatN implements  Eat{@Overridepublic void eat() {System.out.println("正在吃面条!");}
}class Breakfast{public static void main(String[] args){EatB eatB=new EatB();eatB.eat();EatN eatN=new EatN();eatN.eat();DrinkM drinkM=new DrinkM();drinkM.drink();DrinkW drinkW=new DrinkW();drinkW.drink();}}

迪米特法则

迪米特法则(Law of Demeter,LoD)又叫作最少知识原则(Least Knowledge Principle,LKP)

迪米特法则的定义是:只与你的直接朋友交谈,不跟“陌生人”说话
含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性

迪米特法则的优点

迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点。

  • 降低了类之间的耦合度,提高了模块的相对独立性。
  • 由于亲合度降低,从而提高了类的可复用率和系统的扩展性

迪米特法则案例

明星与经纪人:
明星将与粉丝见面、与媒体公司洽谈业务交给经纪人
即明星仅与经纪人交谈

package com.company.DesignPatterns;public class LoDtest
{public static void main(String[] args){Agent agent=new Agent();agent.setStar(new Star("Jay"));agent.setFans(new Fans("粉丝LJJ"));agent.setCompany(new Company("音乐有限公司"));agent.meeting();agent.business();}
}
//经纪人
class Agent
{private Star myStar;private Fans myFans;private Company myCompany;public void setStar(Star myStar){this.myStar=myStar;}public void setFans(Fans myFans){this.myFans=myFans;}public void setCompany(Company myCompany){this.myCompany=myCompany;}public void meeting(){System.out.println(myFans.getName()+"与明星"+myStar.getName()+"见面了。");}public void business(){System.out.println(myCompany.getName()+"与明星"+myStar.getName()+"洽淡业务。");}
}
//明星
class Star
{private String name;Star(String name){this.name=name;}public String getName(){return name;}
}
//粉丝
class Fans
{private String name;Fans(String name){this.name=name;}public String getName(){return name;}
}
//媒体公司
class Company
{private String name;Company(String name){this.name=name;}public String getName(){return name;}
}

合成复用原则

合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)

合成复用原则:要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

意思就是:尽量通过引用对象(UML中的组合、聚合)来实现复用

合成复用原则的优点

类的复用分为:继承复用、合成复用
继承复用虽然有简单和易实现的优点,但它也存在以下缺点。

  • 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用
  • 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护
  • 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化

合成复用的优点:

  • 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用
  • 新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口
  • 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象

合成复用原则案例

继承复用:
汽油汽车、电动汽车继承汽车,然后汽油汽车、电动汽车又有很多子类
明显破坏了父类的封装性,且父类子类耦合度过高,每次改动父类都会所有子类

合成复用:
将颜色、驱动各作为一个引用,这样想要创建一个新的颜色、驱动类型都很简单

总结

设计模式的七大原则:

  • 开闭原则是核心,指导对扩展开放,对修改关闭
  • 里氏替换原则:子类不能重写父类
  • 依赖倒置原则:面向接口编程,通过接口规定编程规范,然后使用类实现
  • 单一职责原则:一个类应当只负责一个职责
  • 接口隔离原则:只给角色提供需要的方法,设计接口要精简单一
  • 迪米特法则:降低耦合,不需直接调用的类通过第三方转发调用
  • 合成复合法则:尽量先考虑合成复合,少用继承复合
  • 开闭原则是核心,其他六个原则各侧重点不同,这七个原则即是面对对象设计的思想

设计模式(2)六大原则(七大原则)相关推荐

  1. 【设计模式】软件设计七大原则

    做好自己 软件设计七大原则 开闭原则OCP(Open-Closed Principle) 依赖倒转原则DIP(Dependence Inversion Principle) 单一职责原则SRP(Sin ...

  2. Java设计模式总结篇:七大原则以及23种设计模式简单介绍

    java设计模式 一.前言 二.七大原则 1.单一原则 2.开闭原则 3.里氏替换原则 4.接口隔离原则 5.依赖倒置原则 6.迪米特法则 7.合成复用原则 三.23种设计模式 1.单例模式(Sing ...

  3. 设计模式(面向对象)设计的七大原则

    声明:本人设计模式模块是集合网上资料和老师课件总结的知识点,如本博客有侵权,本人即刻删. 设计模式(面向对象设计)原则,分别是: 1.开放封闭原则:对扩展开放,对修改关闭 2.单一职责原则:一个类只做 ...

  4. 实例图解设计模式之面向对象设计七大原则

    文章目录 面向对象设计原则详解 面向对象设计原则概述 常用的面向对象设计原则 单一职责原则(Single Responsibility Principe)SRP ★★★★☆ 开闭原则(Open-Clo ...

  5. 设计模式 - 软件设计的七大原则

    文章目录 前言 1. 软件设计模式原则 2. 开闭原则 1. 概念 2. 例子 3. 里氏替换原则 1. 概念 2. 例子 4. 依赖倒置原则 1. 概念 2. 代码 5. 单一职责原则 说明 6. ...

  6. 【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )

    文章目录 一.合成复用原则简介 二.合成复用 与 继承复用 优缺点 三.合成复用原则代码示例 1.继承复用代码示例 2.合成复用代码示例 一.合成复用原则简介 合成复用原则 又称为 组合复用原则 , ...

  7. 【设计模式】软件设计七大原则 ( 里氏替换原则 | 定义 | 定义扩展 | 引申 | 意义 | 优点 )

    文章目录 一.里氏替换原则定义 二.里氏替换原则定义扩展 三.里氏替换原则引申意义 四.里氏替换原则意义 五.里氏替换原则优点 一.里氏替换原则定义 里氏替换原则定义 : 如果 对每一个 类型为 T1 ...

  8. 【设计模式】软件设计七大原则 ( 接口隔离原则 | 代码示例 )

    文章目录 一.接口隔离原则简介 二.接口隔离原则代码示例 ( 反面示例 ) 1.接口定义 ( 接口臃肿 ) 2.实现类 1 3.实现类 2 三.接口隔离原则代码示例 ( 推荐用法 ) 1.接口 1 2 ...

  9. 【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )

    文章目录 一.依赖倒置原则简介 二.面向实现编程代码示例 ( 反面示例 ) 1.顾客类 2.测试类 三.依赖倒置原则代码示例 ( 推荐示例 | 使用接口方法注入 IGood 实现类 ) 1.顾客类 2 ...

  10. 【设计模式】软件设计七大原则 ( 开闭原则 )

    文章目录 一.开闭原则简介 二.开闭原则代码示例 1.商品接口 2.普通商品类 3.折扣商品类 4.测试类 一.开闭原则简介 开闭原则 : 定义 : 一个 软件实体 , 类 / 模块 / 函数 , 对 ...

最新文章

  1. 100题_10 在排序数组中查找和为给定值的两个数字
  2. 输入一个正整数,求它各位数的数字之和
  3. 一起学nRF51xx 10 -  rng
  4. 连接mongodb,kafka异步处理代码
  5. 通过cookie保存并读取用户登录信息
  6. uvalive4836(枚举)
  7. python面向对象:多态与多态性
  8. 前端图片上坐标连线_前端图形学(十三)——弹跳运动的深入之傲娇的小球
  9. 从零开始刷Leetcode——数组(118.119.121)
  10. 用友nc操作手册_铁军人物汤轩宇, 入职两年,她用努力和汗水编制出单户试算操作手册...
  11. 100套PPT模板用于论文答辩、工作方案等
  12. 高仿城通网盘php,城通网盘VIP订单存在业务隐患,可在线提权(含详细修复)
  13. python爬取谷歌学术_对于python抓取google搜索结果的一些了解
  14. 激活office 2007 的方法
  15. 穿越派·派盘 + 思源笔记 = 私人笔记本
  16. 这样美化PPT图表,真的好看到爆~
  17. BDD 100K数据集label转换为yolo训练格式
  18. ESP32温湿度 DHT11 实验
  19. [原创]智能化运维平台部署(gunicorn+nginx+gevent+supervisor部署flask+vue)
  20. 闪游浏览器 0.8 发布,超强地址栏增强等10多项改进

热门文章

  1. Nachos实验实现线程id、限制线程数和更改调度算法(按优先级调度)
  2. Jeff的错题集(九):奥利给!
  3. 我靠,在网站上出现中文的乱码竟然这样解决的
  4. DG备库执行只读open的时候报错
  5. (转)Java学习书籍推荐
  6. 如何安装与配置JDK
  7. 无人驾驶汽车发展史大事纪实
  8. java面试题120题
  9. 熵值法的信息熵值、效用值如何计算?
  10. 【PX4-AutoPilot教程-1】PX4源码文件目录架构分析