美文网首页Java设计模式coding设计模式
设计模式 - SOLID 原则 - 3/n

设计模式 - SOLID 原则 - 3/n

作者: 楷书 | 来源:发表于2018-03-05 07:50 被阅读18次

最近在读 Clean Architecture (豆瓣) ,正好说到了设计模式的5大原则。简写成 Solid ,也就是靠谱、牛逼的意思。

Solid 是由如下的5种原则组成:

  • SRP - Single Responsibility Principle (单一职责)
  • OCP - Open-Closed Principle (开放,封闭)
  • LSP - Liskov Substitution Principle (李氏替换)
  • ISP - Interface Segregation Principle (接口隔离)
  • DIP - Dependency Inversion Principle (依赖倒置)

SRP

简单来说,每一个东西都只有一个职责。这里的 东西 的粒度,可以是一个类,一个文件,一个模块,一个框架等等。

这个原则让我想起了 Unix的哲学:每一个命令只做一件事,并把这事做到极致。所以,经常看到Unix的命令的input/output都是text,这样方便组成pipeline,可以让各种命令相互协作。

对于这个原则的解释还有其他的一些版本,例如:

一个模块,有且只有一个原因令其发生改变。
一个模块只对唯一的用户或模块负责。

为什么要让一个模块只有保持一个责任呢?我觉得有一下的一些原因。

  • 简单。简单的东西总是容易维护和理解的。Keep it simple 是让整个架构灵活、可扩展的前提。
  • 减少错误。当只有一个责任时,错误的几率总是会最小化。当有更多的责任,那这个模块就会和更多的模块耦合。所以会有更多的原因让这个模块变化,也就增加了bug的概率。
  • 高内聚 (cohesion) 。我们希望一个模块是高内聚,低耦合的。

OCP

对扩展开放,对改变封闭

当设计一个类或者一个模块的时候,我们希望遵循能够容易地让使用者扩展,同时不希望让别人来改变类本身的各种功能。

其实,这个原则也好理解。当我们去改变类本身的行为时,势必会改变那些继承和使用这个类的其他用户。这是一个引入bug的危险行为。所以对于改变,我们应该谨慎。但每个使用者又有各自的特殊需求,这时我就应该让类更容易被扩展,让每个使用者自己扩展需求。

swift 为例:

final - 不想让其他的类来继承了
open/public - 对于继承是开放的
extension - 可以对类进行扩展

LSP

单从名字上毫无线索。这个原则源自 Barbara Liskov,一位拿了图领奖的女性计算机牛人。

这个原则的定义如下:

What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

实在难理解,说人话就是:

派生类(子类)对象能够替换其基类(超类)对象被使用。

这是继承和复用的基石。

其中包含了4个含义:

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

这其中第1条有时候是很难做到的,我们一般覆盖父类方法的同时会调用父类方法并且写上一些子类特有的操作。另外的3和4可以参看这里:设计模式六大原则(2):里氏替换原则 - OpenFire_ - 博客园

看个例子:

class Bird {
    func fly() {
        print("Bird is flying")
    }
}

class Kingfisher: Bird {
    override func fly() {
        print("kingfisher is flying")
    }
}

class Penguin: Bird {
    override func fly() {
        print("Penguin cannot fly! :(")
    }
}

var bird: Bird = Bird()
bird.fly()
bird = Penguin()
bird.fly()
bird = Kingfisher()
bird.fly()

这里的 bird 相当于一个指针,它只知道指向的是一个 Bird 。这里,KingfisherPenguin 都是 Bird 的子类,它们可以无缝地替换掉 Bird,对于 bird 这个指针,它并不需要知道这些细节。

ISP

我不需要的东西,别硬塞给我

其实,这个原则和前面的 SRP 有异曲同工之妙。就是要保持接口的简单,不要把各种职责都塞过来。看看能不能把不要的分离出去。这个原则拆分庞大臃肿的接口成为更小和更具体的接口,从而解耦合。

这里一篇文章 - 接口分离原则(Interface Segregation Principle) - 匠心十年 - 博客园 提到了多继承的问题来解决ISP的问题。这里提一下在Swift中是没有多继承的,它用 protocol 来部分解决了这个问题。同时,我觉得这样也更优雅。因为这是对 抽象 在编程,而非 实现

DIP

这个原则可以归纳为两点:

  1. 高层模块不应当依赖于低层模块。两者都应该依赖于抽象。
  2. 抽象不应依赖于实现,实现应该依赖于抽象。

看个例子:

Dependency Inversion

比如我们现在有个自己的App (A),然后使用了 SDWebImage (B),现在我们想要用 Kingfisher (C) 来替换B。这时就变得异常痛苦,因为C和B的接口并不相同。而A已经非常依赖于B的具体接口。

如果我们刚开始就让A和B都依赖于抽象接口 (Interface A),那么当要使用C时,只需让C实现 Interface A,或者实现一个Adapter把C接入然后转换成它的接口就行了。这就是对抽象而不是具体编程的好处。

相关文章

  • 设计模式 - SOLID 原则 - 3/n

    最近在读 Clean Architecture (豆瓣) ,正好说到了设计模式的5大原则。简写成 Solid ,也...

  • JAVA设计模式原则

    一、Solid原则 介绍设计模式中的SOLID原则,分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置...

  • JavaScript 中的 SOLID 原则(一):“S”代表什

    你可能已经了解过一些设计原则或者设计模式,本文主要渐进的讲解了SOLID原则: 不使用SOLID是怎么编写代码的,...

  • js要点总结

    <1> 设计模式原则 solid S && O && L && I && D s single...

  • 设计模式原则(SOLID)

    软件设计应该按照某些原则,这样子能让软件的可复用性和可维护性更强。 单一职责原则 (Single responsi...

  • 设计模式原则SOLID

    一、单一职责原则(SRP) 定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。 问题由来:...

  • 设计模式原则SOLID

    之前花过一段时间整理了设计模式的相关知识。很久没看了,这里简单回顾下。知识温故而知新,尤其是这种原则、思想类的知识...

  • 设计模式 · SOLID原则

    SOLID原则是指: Simple Responsibility Principle,SRP单一职责原则 Open...

  • 设计模式-SOLID原则

    我参考的资料:c语言中文网_软件设计模式概述[http://c.biancheng.net/view/1317.h...

  • iOS相关

    1:设计模式之SOLID原则https://zhuanlan.zhihu.com/p/82324809[https...

网友评论

    本文标题:设计模式 - SOLID 原则 - 3/n

    本文链接:https://www.haomeiwen.com/subject/vyecfftx.html