设计模式-开篇记

前言

之所以开了一个写设计模式的系列,是因为在上家公司之时曾经用过其中的几种,而今将近半年时间过去,由于当初理解的不深入,导致现在已经忘了很多。技能这个东西总是越练越熟的,在我的理解中,语言是交流的工具,例如Java,C等各种计算机语言是我们与计算机交流的一种工具;算法是交流的逻辑和套路;数据结构是语言的组织方式;网络是远程的联系方式。如果把我们写的一个项目当成是一个人对计算机发表的演讲,那么设计模式就是演讲里的奇技淫巧,使我们的项目结构更清晰,扩展更加容易,人与机器皆大欢喜。

UML类图

由于笔记中会有一些类图,所以这里记载一下类图之间的关系。图片来源于https://www.cnblogs.com/pangjianxin/p/7877868.html

(原图出处我也不知道,如有侵权请联系我删除)

Class Diagram

各种不同组件之间的关系如上图,其中组合和聚合容易混淆:组合的关系比较强,例如翅膀是鸟不可分割的一部分,翅膀离开鸟就毫无意义;聚合的关系稍微弱一些,例如大雁在一起成了雁群,但是脱离雁群依然有自己的生命。关联和依赖同样如此,不同气候下人的肤色不一样;但人都需要大气和水,所以人气候是关联关系,但是人依赖大气和水。

设计原则

总纲:开闭原则

开闭原则是接下来说的几种设计原则的总纲,它的定义为:Software entities like classes,modules and functions shoud be open for extension but closed for modifications.

简单来说,就是“对修改关闭,对扩展开放”。

举个例子:

我们原来的交易系统总共有三种订单类型:商城订单,代金券订单,商户买单订单。三种业务对应的业务类型编码是不一样的,按照普通的方式来写,我们是这种方式:
1
2
3
4
5
6
7
if("mallOrder".equals(type)){
businessService.doMallBusiness();
}else if("voucherOrder".equals(type)){
businessService.doVoucherBusiness();
}else{
//......
}

现在如果商城的商品出现打折,通常的做法就是修改doMallBusiness()里面的方法,结算时加入折扣的计算,这种做法的问题在于:所有功能已经通过测试的稳定代码会变得不稳定,乃至重新测试,而通常来说,我们一个类都只有一个测试类,每个类里的测试方法至少有三种:业务逻辑测试、边界测试、异常测试。对于业务复杂的方法可能测试会更多,如果修改了原有代码,需要改的测试方法同样会有很多,甚至会有遗漏的,结果严重会影响到线上程序崩溃。

开闭原则的优点:

  1. 提高模块复用性,模块粒度越小越容易被复用;

  2. 提高可维护性,使用扩展代替修改;

  3. 面向对象开发的需求。

单一职责原则

Single Responsibility Principle,简称SPR。

There should never be more than one reason for a class to change.

这里将引起变化的原因代替职责作为衡量一个接口或者类设计的是否优秀的标准,我对此的理解是,如果一个接口或者类修改,只对其实现类或者子类有影响,那么就说这个接口或者类就是符合单一职责原则的。但是现实项目中最难划分的就是类的职责,需要根据项目和环境来区别对待。我们不能因为用设计原则而用,而需要根据业务场景类设计,也不需要一味死守设计模式而不知变通,最推荐的就是接口的设计做到单一职责,类的设计尽量做到只有一个原因引起变化。

里氏替换原则

Liskov Subsitution Principle,LSP。

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 substited for o2 then S is a subtype of T.

如果每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么说S为T的子类型。也就是说:父类能够出现的地方,子类也能够出现。

依赖倒置原则

Dependence Inversion Prindiple,DIP。

High level modules should not depend upon low level.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

高层模块不应该依赖低层模块,两者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。传统思维的依赖就是需要用什么就使用什么对象,而依赖倒置就是不直接依赖对象,而是依赖对象的抽象。

接口隔离原则

  1. Clients should not be forced to depend upon interfaces that they dont`s use;

  2. The dependency of one class to another one should depend on the smallest possible interface.

建立单一接口,不要建立臃肿庞大的接口,提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口。和单一职责的区别是:单一指责是站在类本身的角度来看,按照职责划分;而接口隔离是站在依赖方来看,有几个模块依赖,就应该有几个接口。

迪米特法则

Law of Demeter(Lod),也称之为最少只是原则(Least Knowledge Principle,LKP),一个类应该对要耦合或者要调用的类知道的最少。即,一个类只跟直接的朋友类通信,什么叫朋友类?出现在成员变量、方法的输入输出参数中的类成为成员朋友类

总结

设计模式是为了让软件的模块之间的耦合程度降到最低,提供模块的可重用性和可维护性。它是前辈们的经验总结,而不是一种强制的要求,一切脱离实际业务的设计都是耍流氓。软件在设计之初,不可能面面俱到,扩展性设计也可能不是那么全面,必要的重构还是需要的,设计模式也不是万能的,用的好才是利器,用不好只会徒增复杂度。

坚持原创、技术分享。请作者喝杯茶吧!