设计模式之七大设计原则

前言

一直想学习一下设计模式,无奈工作繁忙,再加上自己平常也没有足够的耐心,所以这块儿的知识点就一直搁浅下来了。最近准备研究研究设计模式,在这儿记点儿学习笔记吧。设计模式总体来说都是为了使我们的代码耦合性降低,后期更易维护。
这一篇主要介绍一下设计模式的七大原则。


一、七大设计原则介绍

1、开闭原则(Open Close Principle)

1. 定义

  • 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。(用抽象构建框架,用实现扩展细节)

2. 优点

  • 提高软件系统的可复用性及可维护性。

3. 我的理解

  • 如果修改或者添加一个功能,应该扩展原来的代码,而不是修改原来的代码。扩展推荐使用子类继承等方式扩展。3

4. 举例

  • 举例:买车打折问题。
//定义一个接口及一个类。
public interface Car {

    String getName();

    Double getPrice();
}


public class DasAuto implements Car{

    private String name;

    private Double price;

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Double getPrice() {
        return this.price;
    }
}

//此时如果我想给 汽车打个折扣,有以下三种方式。
//1.Car中增加打折的方法。(如果汽车很多,都需要实现该方法,影响原代码)
//2.DasAuto中打折或者增加打折的方法。(同上,需要增加很多方法,影响原代码)
//3.写一个子类,继承DasAuto,增加打折的方法,这样不影响原代码。

public class SaleCar extends DasAuto{

   public Double getSalePrice(){
        return super.getPrice() * 0.8;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        SaleCar car = new SaleCar();
        car.setPrice(210000.00);

        System.out.println("汽车售价" + car.getPrice());
        System.out.println("汽车促销价" + car.getSalePrice());
    }
}
/**
 * 输出:
 *  汽车售价210000.0
 *  汽车促销价168000.0
 *
 */

// 这样的方式不需要修改之前的代码就实现了给促销车打折的方式。

5. UML类图

  • 开闭原则是所有设计原则的基础
    开闭原则
2、里氏代换原则(Liskov Substitution Principle)

1. 定义

  • 如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2,程序P的行为没有发生变化,那么类型S是类型T的子类型。
  • 任何基类可以出现的地方,子类一定可以出现。()

2. 优点与缺点
(1)优点

  • 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性。
  • 提高代码的重用性。
  • 提高代码的可扩展性,实现父类的方法就可以了。

(2)缺点

  • 继承是侵入性的,只要继承,就必须拥有父类的所有方法和属性。
  • 降低了代码的灵活性,子类必须拥有父类的属性和方法,让子类有了一些约束。
  • 增加了耦合性,当父类的常量,变量和方法被修改了,需要考虑子类的修改,这种修改可能带来非常糟糕的结果,要重构大量的代码。

3. 四层含义/规范

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

4. 补充

  • 平常开发中常常使用实现接口的方式,继承用的还不太多。今后的开发中应该多遵循一些基本的规范。
3、依赖倒置原则(Dependence Inversion Principle)

1. 定义

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象。
  • 抽象不应该依赖细节,细节应该依赖抽象。
  • 针对接口编程,不要针对实现编程。

2. 优点

  • 可以减少类之间的耦合性、提高系统的稳定性。
  • 提高代码可读性和可维护性=

3. 我的理解

  • 程序中所有的依赖关系都是终止于抽象类或者接口,这样可以降低类与类之间的耦合。
  • 依赖关系的三种传递方式:接口、构造方法和setter()。
  • 实践:Spring中的依赖注入。
    依赖倒置原则
4、接口隔离原则(Interface Segregation Principle

1. 定义

  • 建立单一接口,不要建立庞大臃肿的接口。
  • 尽量细化接口,接口中的方法尽量少。

2. 注意事项

  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
  • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
    接口隔离原则
5、组合/聚合复用原则(Composite Reuse Principle)

1. 定义

  • 合成/聚合复用原则经常又叫做合成复用原则。该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。

2. 来源

在面向对象的设计中,如果直接继承基类,会破坏封装,因为继承将基类的实现细节暴露给子类;如果基类的实现发生改变,则子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性。于是就提出了组合/聚合复用原则,也就是在实际开发设计中,尽量使用合成/聚合,不要使用类继承。即在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新对象通过向这些对象的委派达到复用已有功能的目的。就是说要尽量的使用合成和聚合,而不是继承关系达到复用的目的。

3. 作用

组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。 由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

4. 使用总结

  • 子类是基类的一个特殊种类,而不是基类的一个角色。区分“Has-A”和“Is-A”。只有“Is-A”关系才符合继承关系,“Has-A”关系应当用聚合来描述。
  • 永远不会出现需要将子类换成另外一个类的子类的情况。如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。
  • 子类具有扩展基类的责任,而不是具有置换掉(override)或注销掉(Nullify)基类的责任。如果一个子类需要大量的置换掉基类的行为,那么这个类就不应该是这个基类的子类。
  • 只有在分类学角度上有意义时,才可以使用继承。不要从工具类继承。

5. 补充

  • 这里面的内容都为引用。看到一篇大神的文章,感觉写的很好。
6、迪米特法则(Law Of Demeter)

1. 定义

  • 一个对象应该对其他对象保持最小的了解。又叫最小知道原则。

2. 优点

  • 降低类与类之间的耦合。

3. 通俗理解

  • 只与直接的朋友通信。
  • 类之间只要有耦合关系,就叫朋友关系。
  • 成员变量、方法参数、方法返回值中的类为直接朋友。
  • 局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

迪米特法则4. 我的理解

举个例子来说,比如校长让老师检查班级里孩子们实践报告完成的情况。此时校长不需要知道老师是如何检查作业的,校长不需要与孩子有关联关系。校长只需要指定一名老师,然后坐等结果就好。

7、单一职责原则(Single Responsibility Principle)

1. 定义

  • 不要存在多于一个导致类变更的原因。
  • 一个类只负责一项职责,应该仅有一个引起它变化的原因。

2. 优点

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

二、总结

1.合成/聚合复用优缺点和继承复用优缺点?

  • 合成复用
    (1)优点:新对象存取成分对象的唯一方法是通过成分对象的接口;这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的;这种复用支持包装;这种复用所需的依赖较少;每一个新的类可以将焦点集中在一个任务上;这种复用可以在运行时动态进行,新对象可以使用合成/聚合关系将新的责任委派到合适的对象
    (2)缺点:通过这种方式复用建造的系统会有较多的对象需要管理。
  • 继承
    (1)优点: 新的实现较为容易,因为基类的大部分功能可以通过继承关系自动进入派生类;修改或扩展继承而来的实现较为容易。
    (2)缺点:继承复用破坏包装,因为继承将基类的实现细节暴露给派生类,这种复用也称为白箱复用;如果基类的实现发生改变,那么派生类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,不够灵活。

2. 单一职责与接口隔离的区别

  • 单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
  • 单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节; 而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。

三、尊重原创

java七大设计原则

23种设计模式全解析

六大设计原则之里氏替换原则

设计模式六大原则例子(四)–依赖倒置原则(DIP)例子

组合/聚合复用原则详解–七大面向对象设计原则(7)

感谢阅读。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值