我正在参加「掘金·启航计划」
什么是SOLID原则
SOLID原则由5个设计原则组成:单一职责原则,开闭原则、里式替换原则、接口隔离原则和依赖反转原则。取这5个原则的首字母S O L I D 命名为单一职责原则
单一职责原则
单一职责原则(Single Responsibility Principle),缩写为 SRP 定义是:
A class or module should have a single responsibility。
一个类或者模块只负责完成一个职责(或者功能)。
实践标准
职责足够单一,类与类之间的关系没有相互依赖(低耦合)。
避免设计出大而全的类,把与类不相关的功能拆分出去(高内聚)。
思考:是不是拆分的越细越好?
我的答案是否定的。拆分的越细反而会降低内聚。违背了初衷。所以这个标准的掌握就尤其重要。
刚开始设置颗粒度比较大的类,从业务逻辑出发,经常审视自己的代码,吾日三省吾代码,这个类的代码行数,方法是不是很多。需不需要做拆分,这个方法没办法起名字了。这个类依赖性比较强等等。这时候可以考虑进行类的拆分,遵循单一职责原则。
开闭原则
开闭原则 (The Open/Close Principlee), 缩写为 OCP 定义是:
Software entities (modules, classes, functions, etc) should be open for extension, but closed for modification.
软件中的实体(类、模块、函数等等)应该对于扩展是开放的,但是对于修改是封闭的
里氏替换原则
(Liskov Substitution Principlee), 缩写为 LSP 定义是:
Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。
子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏
实践标准
一条更有意义的描述:“Design By Contract”,中文翻译是“按照协议来设计”
子类在设计的时候,要遵守父类的行为约定(或者叫协议)。父类定义了函数的行为约定,那子类可以改变函数的内部实现逻辑,但不能改变函数原有的行为约定。这里的行为约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至包括注释中所罗列的任何特殊说明。实际上,定义中父类和子类之间的关系,也可以替换成接口和实现类之间的关系。
- 子类违背父类声明要实现的功能
- 子类违背父类对输入、输出、异常的约定
- 子类违背父类注释中所罗列的任何特殊说明
第三点说明:父类中定义的 withdraw() 提现函数的注释是这么写的:“用户的提现金额不得超过账户余额……”,而子类重写 withdraw() 函数之后,针对 VIP 账号实现了透支提现的功能,也就是提现金额可以大于账户余额,那这个子类的设计也是不符合里式替换原则的。
依赖反转原则
(Dependency Inversion Principle), 缩写为 DIP 定义是:
High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstractions.
高层模块(high-level modules)不要依赖低层模块(low-level)。高层模块和低层模块应该通过抽象(abstractions)来互相依赖。除此之外,抽象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖抽象(abstractions)。
迪米特法则
(Law of Demeter), 缩写为 LOD 定义是:
Each unit should have only limited knowledge about other units: only units “closely” related to the current unit. Or: Each unit should only talk to its friends; Don’t talk to strangers.
每个模块(unit)只应该了解那些与它关系密切的模块(units: only units “closely” related to the current unit)的有限知识(knowledge)。或者说,每个模块只和自己的朋友“说话”(talk),不和陌生人“说话”(talk)。
实践标准
- 不该有直接依赖关系的类之间,不要有依赖;
- 有依赖关系的类之间,尽量只依赖必要的接口(也就是定义中的“有限知识”)。
第一点举例,获取每天走的步数一个step类,那么接受的参数是user类,这样认为user类和step类是由依赖关系的。那其实step这个类不只是想获取user类的步数,还有dog类的呢。这时候就需要修改step类了。调整一下参数变成把user和dog的步数给step就可以了。
第二点举例:类具有序列化反序列化方法。依赖序列化的类,不想依赖反序列化。通过接口隔离原则实现。
DRY原则
(Don’t Repeat Yourself), 缩写为 DRY 定义是:
中文直译为:不要重复自己。将它应用在编程中,可以理解为:不要写重复的代码。
实践标准
实现逻辑重复、功能语义重复、代码执行重复。