本文共 2426 字,大约阅读时间需要 8 分钟。
解释:
应该有且仅有一个原因引起类的变更。一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,它就负责一件事情。
举例:
一个视频播放软件,包含一个播放器类,这个类包含视频播放接口和音频播放接口,显然这样的设计是不符合SRP原则的。因为音频播放和视频播放需求的修改都会导致播放器这个类的结构发生改变。符合单一原则的设计是,将视频播放单元和音频播放单元各建一个类,播放器类继承这两个类,构成客户端。
单一职责原则最大的难点在于职责的划分,粒度的把控。应根据项目特点和业务流程特点进行考虑。但基本思想不变。
优点:
解释:
只要父类出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道父类还是子类。
里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了4层含义:
采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续执行。
举例:
对于一个鸟类,可以衍生出麻雀、喜鹊、布谷等子类,这些子类都可继承鸟类的鸣叫、飞行、吃食等接口。而对于一个鸡类,虽然它在生物学上属于鸟类,但它不会飞,那么符合LSP设计原则的情况下,鸡就不应该是鸟的一个子类:在鸟类调用飞行接口的地方,鸡类并不能出现。如果鸡类要使用鸟类的接口,应该使用关联关系,而不是继承关系。
解释:
高层模块不应该依赖于低层模块,两者都应该依赖其抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
举例:
一个自动驾驶系统类AutoSystem,两个汽车类TruckCar(卡车类),SedanCar(小轿车类),两个汽车类实例作为AutoSystem的参数,AutoSystem类中调用两个汽车类实例中的run(启动)、turn(转弯)、stop(停车)方法来实现自动驾驶。这是不符合DIP设计原则的,因为高层模块(AutoSystem)依赖了底层模块(汽车类)。
正确的做法应该是存在一个汽车基类或抽象类Car,Car基类中实现run、turn、stop方法,汽车子类继承这个基类。AutoSystem自动驾驶系统类调用汽车基类的run、turn、stop方法实现自动驾驶(依赖抽象思想)。
解释:
类间的依赖关系不应该建立一个大的接口,而应该建立其最小的接口,即客户端不应该依赖那些它不需要的接口。这里的接口的概念是非常重要的。从逻辑上来讲,接口可以指一些属性和方法的集合;从业务上来讲,接口就可以指特定业务下的接口(如函数,URL调用等)。接口应该尽量小,同时仅留给客户端必要的接口,弃用没有必要的接口。
举例:
如果要根据具体的数据,生成饼图、直方图、表格,这个类该如何设计?如果将生成饼图、直方图、表格等“接口”(这里的接口就是“操作”的集合的概念)写在一个类中,是不符合接口隔离原则的。符合ISP原则的设计应该是设计三个类,每个类分别实现饼图、直方图、表格的绘制。
接口隔离原则和单一职责原则一样,涉及到粒度的问题,解决粒度大小,同样依赖于具体的业务场景,需要读者根据实践去权衡。原则:
解释:
一个对象应该对其它对象有最少的了解。通俗讲就是一个类对自己依赖的类知道的越少越好,也就是对于被依赖的类,向外公开的方法应该尽可能的少。
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一类的某一个方法的话,可以通过第三者转发这个调用。
举例:
和陌生人说话。甲和朋友乙认识,乙和陌生人认识,而甲和陌生人不认识。甲想要和陌生人说话,就必须通过朋友乙,这是负责迪米特法则的,即只和朋友交流,拒绝和自己不认识不熟悉的人交流。
缺点:
迪米特法则不希望类之间建立直接的联系。如果真的有需要建立联系,也希望能通过它的中介类来转达。因此,应用迪米特法则有可能造成的一个后果就是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系——这在一定程度上增加了系统的复杂度。
解释:
一个软件实体,如类、模块、函数等,应该对扩展开放,对修改关闭。
对扩展开放,意味着模块的行为是可以扩展的,当高层模块需求改变时,我们可以对低层模块进行扩展,使其具有满足高层模块的新功能;对修改关闭,即对低层模块行为进行扩展时,不必改动模块的源代码。
举例:
假设一个原始基类水果类,苹果类是它的派生类,苹果中包含水果的各种属性,如形状、颜色等;另有两个类,农民类和花园类,最高层次(业务层次)为农民在花园种苹果。如果此时,农民决定不种苹果了,改种梨,符合OCP原则的设计应该为基于水果类构建一个新的类,即梨类(对扩展开放),而并不应该去修改苹果类,使它成为一个梨类(对修改关闭)。修改应仅在最高层,即业务层中进行。
转载地址:http://ivivb.baihongyu.com/