设计模式之设计原则(七大原则)

单一职责原则(Single Responsibility Principle)

  • 介绍
    • 一个类只负责一项职责
    • 如果A类有职责1和职责2,当职责1需求修改而改变A类时,可能导致职责2执行错误
    • 所以需要A类的粒度分解为A1类、A2类
  • 好处
    • 能降低类的复杂度
    • 能提高类的可读性和可维护性
    • 降低方法变更引起的风险
  • 注意
    • 通常情况我们应当遵守单一职责原则
    • 但如果逻辑足够简单,可以在代码级违反单一职责原则
    • 如果类中方法数量足够少,可以在方法级别保持单一职责原则
      • 即可以分成少个不同职业的方法

接口隔离原则(Interface Segregation Principle)

  • 介绍
    • 客户端(类)不应该依赖(实现)它不需要的接口(一个类对另一个类的依赖应该建立在最小接口上)
    • 如果接口1中有5个方法,A类实现了接口1
      • A类只需要使用接口1其中的3个方法
      • 但此时A类实现接口1需要实现5个方法,此时违反了接口隔离原则
      • 我们可以将接口1拆分成接口1和接口2,接口1包含3个方法,接口2包含另外2个方法
      • 此时A类实现接口1则只需要实现3个方法,满足接口隔离原则
  • 注意
    • 接口隔离不一定是需要将5个方法拆分成5个接口,我们只需要满足最小接口
    • 比如A类需要3个方法,B类需要另外2个方法,我们只需要将1个接口拆分成2个接口

依赖倒转(倒置)原则(Dependence Inversion Principle)

  • 介绍
    • 高层模块(类)不应该依赖低层模块(类),二者都应该依赖其抽象
    • 抽象不应该依赖细节,细节应该依赖抽象
    • 依赖倒转的中心思想是面向接口编程
    • 基于以下设计理念
      • 相对于细节的多变性,抽象的东西要更稳定
      • 以抽象为基础搭建的架构比以细节为基础的架构更稳定
      • java中,抽象指的是接口或抽象类细节就是具体的实现类
    • 使用接口或抽象类的目的是制定好规范,不涉及任何具体的操作,它们的实现类则负责展现各自的细节
  • 依赖关系传递的三种方式
    • 接口传递
    • 构造方法传递
    • setter传递 [setter(arg)]
  • 注意事项和细节
    • 低层模块(类)尽量要有抽象类/接口,或者两者都有,这样程序稳定性更好
      • 变量的声明类型尽量是抽象类/接口,此时变量引用和实际对象之间就存在了一个缓冲层,有利于程序的扩展和优化
      • 实际上就是接口作为声明的变量来new实现类
      • B类实现了A接口,在main方法中创建B类A b = new B();
    • 继承时遵循里氏替换原则
  • 个人理解
    • 每个类都尽量实现接口/抽象类
    • 在接口/抽象类中制定类的规范,细节则在类中进行编写

里氏替换原则(Liskov Substitution Principle)

  • 里氏替换原则主要讲如何正确的使用继承
  • 对继承的思考
    • 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法进行任意的修改,就会对整个继承体系造成破坏
    • 继承在给程序设计带来便利的同时,也带来了弊端
      • 使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性
      • 如果A类被其它的类所继承,则当A类需要修改时,就必须考虑所有的子类,并且A类修改后,所有涉及到子类的功能都有可能产生故障
      • 正因如此,我们应该如何正确的使用继承?里氏替换原则就是如何正确使用继承的指导原则
  • 介绍
    • 所有引用基类的地方必须能透明地使用其子类的对象
    • 核心:在使用继承时遵循里氏替换原则,在子类中尽量不要重写父类的方法
    • 里氏替换原则告诉我们,继承实际上让两个类的耦合性增强了,在适当的情况下我们可以通过聚合、组合、依赖关系来解决问题(在类中声明/使用另外的类的方法,而不用继承)
  • 例子
    • 违背里氏替换原则
      • A类有1个方法,B类继承A类,实现了A类的方法;
      • 但此时B类不小心重写了A类的方法(实际中可能是忘了曾经重写过该方法)
      • B类新添加了1个方法使用到重写的方法
      • 此时B类新添加的方法运行的结果并不是期待的结果
    • 修改为符合里氏替换原则
      • 将A、B类共同的基础的功能对应的方法提取出来,放到新的接口/抽象类中,我们假设该接口/抽象类为Base(此次例子方法比较少,因此不需要)
      • A、B类都实现该接口/抽象Base,此时就可以写各自的方法了
      • 如果B类需要用到A类的方法,则只需要在自身中声明A类(组合关系),通过A类的对象调用其方法即可
        • 在B类中A a = new A();

开闭原则(ocp)(Open Closed Principle)

  • 介绍
    • 开闭原则是编程中最基础、最重要的设计原则
    • 一个软件实体如类、模块和函数应该对扩展开放**(对提供方提供扩展),对修改关闭(对使用方关闭修改)**,用抽象构建框架,用实现扩展细节(类似依赖倒转)
    • 当软件需要变化时,尽量通过扩展软件实体的行为来变化(添加类/模块/方法),而不是通过修改原有的代码实现变化
    • 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则
  • 个人理解
    • 将不同类中共有的功能抽出到接口/抽象类中,具体其它细节则在类中实现
    • 当我们做完功能后,如果需要添加其它功能,可以选择以下方式来增加其它功能,这就是扩展
      • 添加类并实现接口
      • 添加类并实现抽象类
      • 添加方法
      • 添加模块
    • 如果使用了同一个接口,也可以利用多态的特性,用接口作为声明变量,实现类创建对象
      • A b = new b()

迪米特法则(Demeter Principle)

  • 介绍
    • 一个对象应该对其它对象保持最少的了解
    • 类与类关系越密切,耦合度越大
    • 迪米特法则也称为最少知道原则
      • 一个类对自己依赖的类知道的越少越好。
      • 对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部
      • 对外除了提供public的方法,不对外泄露任何信息
    • 迪米特法则最简单的定义
      • 只与直接朋友通信
    • 什么是朋友关系
      • 首先需要了解耦合的方式:依赖、关联、组合、聚合等
      • 每个对象都会与其它对象有耦合关系,只要两者之间有耦合关系,就称两者为朋友关系
    • 什么是直接朋友
      • 如果出现成员变量、方法参数、方法返回值中的类为直接朋友
        1. A类中定义成员变量是B类对象
        2. A类的方法参数是B类对象
        3. A类方法的返回值是B类对象
      • 出现在局部变量中的类不是直接朋友
        • 在方法中创建其它类的对象,在A类方法的方法体中创建B类的对象B b = new B();
        • 例外情况:如果B类对象是A类方法的参数或返回值,说明是直接朋友
      • 陌生的类最好不要以局部变量的形式出现在类的内部,这样就不是直接朋友(违反迪米特法则)
  • 细节
    • 迪米特法则的核心是降低类之间的耦合
    • 由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低 类/对象 之间的耦合关系并不是要求完全没有依赖关系
  • 个人理解
    • 例子理解
      • 如果A类方法中需要用到B类的对象,并且B类对象也不是A类方法的参数/返回值,此时就不是直接朋友
      • 此时我们就可以将B类对象封装到某个类的方法中(该方法与B类对象是直接朋友)
    • 迪米特法则重点
      1. 降低类之间的耦合度
      2. 了解直接朋友
      3. 减少不是直接朋友的类,达到降耦合(将不是直接朋友的类封装到 其它 是该类的直接朋友的 类/方法中)

合成复用原则(Composite Reuse Principle)

核心:尽量使用合成/聚合的方式,而不是继承

设计原则核心思想

  • 找出可能需要变化之处,将它们独立出来,不要和不需要变化的代码相混。
  • 面向接口编程,而不是针对实现编程
  • 为了交互对象之间的松耦合设计而努力(降低对象之间的耦合)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值