标签:
单一责任原则(SRP)
The Single Responsibility Principle
引用老外的一张经典图解:
单一职责原则要求“一个类只能有一个职责”,引起这个类变化的唯一原因只能是这个职责。当类有多个职责的时候,应当把其他的职责分离出去,分别创建类来完成。
例如:
类Modem实现了调制解调器的功能,但却实现了两个职责(当然你也可以说是四个职责,这个是按照应用场景来分的),连接的建立和终端,数据的传输和接收。那么问题来了,如果要修改数据传输方式的话,就需要修改Modem类,那么所有依赖Modem的元素都需要修改。上图的解决方法是重构Modem,从中抽出两个接口,Connection专门负责连接,DataChannel负责数据传输。最后有ModemImplementation实现这两个接口。
开闭原则。(OCP)
The Open Closed Principle
当你穿外套的时候,不需要做开胸手术。
“模块应该对扩展开放,对更改关闭“ 1. ”对扩展开放“,当需求改变时,我们可以最模块进行扩展,使其具有满足那些改变的新行为,使软件具有适应性和灵活性。2. ”对更改关闭“,当我们需要扩展新功能时,应编写新的代码,不应该修改原来的代码。
对于OCP原则来说,抽象是关键。例如:如果多个client依赖于一个具体的server,当server需要扩展新功能时,将导致所有的client都可能改动。解决方法就是抽象出来一个server,使client依赖这个抽象的server,仅说明哪些不易改变的一组服务,使其子类提供具体的实现和扩展,这样具体的实现和扩展的修改就不会影响到client。
对于OCP的另外一种理解是”封装可变性原则“(EVP)。其核心思想是”找到系统中的可变元素,将其封装起来“。EVP有两个要点:
1. 可变性不应散落在代码的各个角落,而应封装到一个类中。
2. 一种可变性不应该和另一种可变性混合在一起。
你允许什么发生改变,但不能让这个改变导致重新设计。OCP是面向对象设计的核心所在,但实际中滥用OCP也是错误的,正确的做法是仅对程序中呈现出频繁变化的部分进行抽象和封装。
里氏替换原则。(LSP)
The Liskov Substitution Principle
真鸭子和玩具鸭子都抽象鸭子,但是玩具鸭子需要电池,这就是个错误的抽象。
思想:继承必须确保父类所拥有的性质在子类中仍然成立,当一个子类的实例能够替换任何其父类的实例时,它们之间才具有is-a-kind-of-A关系.只有当一个子类(派生类)可以替换掉其父类(基类)而软件功能不受影响时,基类才能被复用,派生类也才能在基类的基础上增加新的行为.
其本质是在同一个继承体系中的对象应该有共同的行为特征.
例如:企鹅不属于鸟类,因为企鹅不会飞,所以企鹅不能继承鸟类。
接口分离原则(ISP)。
The Interface Segregation Principle
提供尽可能”小“的,单独的接口,而不是提供一个大的接口。
思想:多个和客户相关的接口要好于一个通用接口.如果一个类有几个使用者,与其让这个类再如所有使用这需要使用的所有方法,还不如为每个使用者创建一个特定接口,并让该类分别实现这些接口.。不要让接口中有和该接口功能无关的多余的方法。
如上图所示,类A依赖接口I中方法1\方法2\方法3, 类B是对类A依赖的实现, 类C依赖于接口I中的方法方法1\方法4\方法5, 类D是对类C依赖的实现.对于类B和类D中都存在用不到的方法, 但是由于实现了接口I,所以需要实现这些不用的方法。可以发现接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用,实现类中都必须去实现这些方法,如类B中方法4和方法5,类D中方法2和方法3,显然这样的设计不适用..
接口隔离原则即尽量细化接口,接口中的方法尽量少,为各个类建立专用的接口,而不是试图去建立一个庞大而臃肿的接口提供所有依赖于他的类去调用.
说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。
其一,单一职责原则原注重的是职责,而接口隔离原则注重对接口依赖的隔离.
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建.
依赖倒置原则。(DIP)
The Dependency Inversion Principle
思想:高层模块不应该依赖低层模块,二者都应该依赖于抽象.
换句话说:要依赖于抽象,而不要依赖于具体实现;高层是功能和策略,低层是具体实现;编程程序语言就是需要针对接口编程而不要针对实现编程.
1.高层模块只应该包含重要的业务模型和策略选择
2.低层模块则是不同业务和策略的实现
3.高层抽象不依赖高层和底层模块的具体实现,最多依赖低层的抽象
4.低层抽象和实现也只依赖于高层抽象
例如:
现在司机eastmount不仅要开奔驰车,还要开宝马车,又该怎么实现呢?自定义宝马汽车类BMW,但是不能开,因为eastmount没有开宝马车的方法,出现的问题就是:
司机类和奔驰车类之间是一个紧耦合关系,这导致了系统的可维护性大大降低,增加新的车类如宝马BWM汽车就需要修改司机类drive()方法,这不是稳定性而是易变的.被依赖者的变化竟然让依赖者来承担修改的代价,所以可以通过依赖倒置原则实现.
如下图所示,通过建立两个接口IDriver和ICar,分别定义了司机的职能就是驾驶汽车,通过drive()方法实现;汽车的职能就是运行,通过run()方法实现.
我们讨论了5个设计原则,最重要的是OCP,其他四个都附属于开闭原则,违背其他四个原则都直接或间接违背OCP。
标签:
原文地址:http://my.oschina.net/shyl/blog/525465