Java设计模式中软件的设计原则篇
一、单一职责原则(Single Responsibility Principle--SRP)
就一个类而言,应该仅有一个引起它变化的原因。如果一个类的职责太多,就等于把这些职责耦合在一起,一个职责的变化可能会影响这个类其他职责能力,这种耦合就会导致脆弱的设计。当发生变化时,设计会遭受到意想不到的破坏。软件设计真正要做的,就是发现职责然后将这些职责相互分离。
那如何判断是否应该分离出类来?如果你能想到多余一个动机去改变这个类,那么这个类就有多余一个的职责,就应该考虑类的分离。
比如,我们在设计俄罗斯方块时候,因为界面逻辑表示只是根据数据去进行擦除和绘制,而游戏逻辑则控制方块的下落、旋转、碰撞等。
界面表示逻辑与游戏逻辑需要分离,这样不管你界面怎么换,游戏逻辑都可以复用。
二、开闭原则(Open Close Principle--OCP)
开闭原则就是说对扩展开放,对修改关闭。软件实体(类、模块、函数等)应该可以扩展,但是不可修改。在我们最初编写代码时,假设变化不会发生,当发生变化时,我们就创建抽象来隔离以后的变化。程序的改动是通过增加新的代码,而不是修改现有的代码。开闭原则是面向对象设计的核心所在。
比如,下图,如果我们按照下图上半部分设计代码,将运算过程放在客户端类中,那么后续扩展都需要修改客户端类。而下半部分,如果要增加减法计算,只需要新增减法操作类就行。
三、依赖倒转原则(Dependence Inversion Principle--DIP)
所谓依赖倒转(也叫倒置)原则(Dependence Inversion Principle),就是抽象不应该依赖细节,细节应该依赖于抽象。换句话说,我们要针对接口编程,而不是针对实现。
依赖倒转的原则的具体内容:
- 高层模块不应该依赖于底层模块,两个都应该依赖于抽象
- 抽象不应该依赖细节,细节应该依赖抽象
如何理解高层模块不应该依赖于底层模块呢?我们看下里氏代换原则,就能明白。
四、里氏代换原则(Liskov Substitution Principle--LSP)
里氏代换原则(Liskov Substitution Principle LSP)是Liskov 女士在1988年发表的,翻译过来简言之就是:子类型必须能够替换掉他们的父类型。只有当子类可以替换掉父类,软件单位的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。如下图:
也正是由于子类型的可替换性才使得父类型在的模块在无需修改的情况下就可以扩展。反过头来理解下依赖倒置原则,是不是明白了?
五、接口隔离原则(Interface Segregation Principle)
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
使用多个专门的接口比使用单一的总接口要好。
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
六、合成复用原则(Composite Reuse Principle)
在面向对象设计中,有两种基本的办法可以实现复用:
第一种是通过合成/聚合,即合成复用原则,含义是指,尽量使用合成/聚合,而不是使用继承。
第二种就是通过继承。
要正确地选择合成/复用和继承的方法是,只有当以下的条件全部被满足时,才应当使用继承关系:
合成复用原则就是指在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用其已有功能的目的。简言之:要尽量使用组合/聚合关系,少用继承。比如我们在策略模式中,在CashContext类中持有了CashSuper类,而不是去继承它。
七、迪米特法则(Law of Demeter--LoD)
迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),它的解释是如果两个类不必直接通信,那么这两个类就不应该发生直接作用。如果一个类需要调用另外一个类的方法,可以通过第三者转发这个调用。也就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。英文简写为:LoD。
迪米特法则的前提是在类的结构设计上,应该尽量降低成员的访问权限。迪米特法则的根本思想是强调了类之间的松耦合,也就是说类之间的耦合越弱,越有利于复用。
比如,小王入职,需要在IT部领电脑,他不需要认识IT部的任何人,通过前台一个电话:喂,IT部吗?请协助人员给小王配置电脑。
下一篇: Java设计模式篇(四)--装饰模式详解