目录

面向对象设计原则


面向对象设计原则

1 SOLID 法则

S   Single Responsibility Principle   单一贵任原则
O   Open Closed Principle             开放封闭原则
L   Liskov Substitution Principle     里氏替换原则
I   Interface Segregation Principle   接口分离原则
D   Dependency Inversion Principle    依赖倒置原则

1.1 单一职责原则

  • 将过多的职责耦合在一个类中导致了脆弱设计
  • 职责是变化的原因,只有一个变化的原因
  • 如果应用程序变化的方式总是导致两个方法同时变化,则不应该分离他们
  • 把业务规则和持久化子系统绑定在一起是自讨苦吃,这违反了单一职责原则。可以使用 Facade 或者 Proxy 模式进行重构,以解除这种耦合
  • 软件设计要做的,就是发现职责并把那些职责相互分离
  • 职责越单一,越利于复用
  • 利于单元测试
  • 高内聚,密切相关的放在一起;

1.2 开闭原则

  • 对扩展开放,对修改闭合
  • 面向对象可复用设计的第一块基石
  • 其他设计原则是开一闭原则的的手段和工具
  • 抽象是关键
  • Linux 设备驱动:抽象,两数指针;封装,static
  • 工厂方法模式符合,简单工厂模式部分符合(工厂类需要修改)

1.3 里氏替换原则

  • 任何基类可以出现的地方,子类一定可以出现:
  • ISA 关系是就行为而言的:
  • 考星继承的合理性
  • 反例:功能少于基类的派生类,正方形从长方形继承,派生类抛出基类不能预计的异常。
  • 策略模式,客户程序依赖于策略的抽象父类,根据需要替换为具体的策略子类。
  • 组合模式,客户程序以一种一致的方式(相同的接口)访问不同的子类(叶子节点和树枝节点)

1.4 接口隔离原则

  • 使用多个专门的接口比使用单一的总接口要好
  • 一个类对另外一个类的依赖性应当是建立在最小的接口上
  • 为不同的客户提供不同的接口
  • 修改影响到哪些客户,很明确
  • JAVA 的接口,C++ 的多重继承
  • 迭代模式,迭代器只为客户暴露有限的接口

1.5 依赖倒置原则

  • 要依赖于抽象,不要依赖于具体
  • 具体依赖抽象,而不是抽象依赖具体。
  • 面向接口编程,而不是面向具体编程
  • 使用接口和抽象类进行变量类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。
  • 一个对象持有另外一个具体对象的引用可能破坏了 DIP
  • 抽象一一稳定的,单一的,不变的,共性,事物本质的特质,(核心业务逻辑,业务模型,领域模型)。
  • 具体一一可变的,多样的,细节,具体实现。

2 更多法则

2.1 迪米特法则

  • 只与你的朋友们通信(朋友圈,子系统,门面模式)
  • 不要跟“陌生人”讲话。(最少依赖原则,老死不相往来)
  • 通过朋友的朋友访问陌生人(中介者模式)
  • 最少知识/最少依赖。
  • 限定通信/依赖的宽度和深度 (a。getB(。getc。getD0)。fun(),依赖的深度太深,违反最少知识/最少依赖)

2.2 面向接口编程

  • 面向抽象编程,抽象是稳定的,程序自身变的稳定,灵活度增加。
  • 成员变量,函数参数,函数返回值,局部变量都是抽象类
  • 函数参数:draw(Shape shape) Vs draw (Rectangle rectangle)
  • 成员变量:Shape shape VS Rectangle rectangle
  • 成本增加,多了抽象层
  • 时机,确定需要灵活度是再增加抽象层

2.3 专家模式

  • 谁拥有数据,谁就来履行相应的职责
  • 反例:一个对象要频繁访问另一对象的数据,或调用另一对象的方法;纯数据类。

2.4 合成/聚合复用原则

  • 优先使用合成/聚合复用,而不是继承

  • 合成/聚合复用的优点

    • 通过接口访问成分对象(抽象接口),耦合度低。
    • 黑箱复用,因为成分对象的内部细节是容器对象所看不见的,符合最小知识/ 依赖。
    • 可以在运行时间内动态进行(替换为新对象),10c 依赖注入
  • 继承的缺点

    • 继承复用破坏封装,因为继承将超类的实现细节暴露给子类。由于超类的内部细节常常是对于子类透明的,所以这种复用是透明的复用,又称“白箱”复用
    • 如果超类发生改变,那么子类的实现也不得不发生改变。
    • 从超类继承而来的实现是静态的,不可能在运行时间内发生改变
    • 具体继承/抽象继承
  • 松耦合-高内聚

  • 高内聚,密切相关的放在一起;所有属性在在同一个计算中被用到, 有同样的生命周期。

    • 反例,一组属性被一组成员函数使用,另一组属性被另一组成员函数使用;极端情况,某个属性仅被一个方法使用(应该成为局部变量,参数,或独立的对象)
  • 耦合(或者依赖)关系的种类

    • 具体耦合(Concrete Coupling)
    • 抽象耦合(Abstract Coupling),使用接口和抽象类进行变量类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。
  • 对象之间的关系:依赖,关联,聚合,组合

  • 单一职责在讲高内聚,迪米特法则在讲松耦合。