设计模式的四大原则
这几天论文写完了,开始收拾起本该寒假就读完的《大话设计模式》。整本书读起来还是不错的,语言诙谐有趣,以生活中的例子为切入点,使读者容易理解。比较适合面向对象语言的初学者或者中级人员学习。在这个系列学习中,我们先从设计模式的四大原则开始学起
四大原则:
* 单一职责:就一个类而言,应该仅有一个引起它变化的原因。
* 开闭原则:软件实体(类,方法。。)应该可以扩展,但是不能修改。
* 依赖倒置:抽象不应该依赖于细节,细节应该依赖于抽象。
* 里式替换:子类型必须能够替换掉他们的父类型。
单一职责
以开发一个俄罗斯方块为例。我们可以把方块的下落,旋转,移动,碰撞判断等逻辑和游戏页面分离开来,也可以写在一起。但是界面的变化和游戏本身的逻辑之间是没有关系的。
其实软件设计的主要内容就是发现职责并把这些职责分离开来。如果我们能想到有多于一个动机去改变一个类,那么这个类就具有多于一个职责。我们就要想办法将类的职责进行分离。
因为如果一个类的职责过多,就等于把这些职责耦合在一起了,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力,使整个设计变得脆弱。
开闭原则
开闭原则从字面意思来解释即对扩展开放,对修改封闭。
整个开闭原则所要描述的问题是怎样的设计可以使我们的系统在面对突然变化的需求时,可以尽量少的修改即可满足需求。
以上班考勤为例。针对上班的8小时工作制,有的公司规定早9晚6,有的公司则规定早8晚5。所有的规定都是面向8小时封闭,面向起始时间开放的。甚至对以业绩为指标的公司,可以对8小时工作制都开放,但是对员工的业绩必须封闭。这里就需要找清自己想要达到什么目的。
当然,在我们写代码的时候,我们假设变化不会发生,但是当变化发生时,我们就应该创建抽象类来隔离以后发生的同类变化。比如需要创建一个加法运算。我们可以创建一个Client类来进行执行。一个加法类来进行加法运算。但是当我们需要在Client中支持减法的时候,我们就应该考虑抽象出一个运算类来进行实际的运算操作和Client的隔离。同时如果我们需要增加乘法,除法类的时候,只需新增加类即可,不许要在修改Client了。这样可以达到对扩展开放,对修改封闭的目的。
依赖倒置
其实整个依赖倒置原则的通俗的将就是应该面向切口编程。
这里书中对倒置的解释引用了数据库连接中高层模块依赖与底层模块的例子。但是我觉得直接看主板和内存,CPU等的关系更容易理解。即如果内存,CPU等坏了,我们直接换掉了就可以了。但是如果作为底层模块的主板坏了,我们是不是得把整个电脑换了才可以呢?答案是当然不用。因为主板和内存都是面向接口的,所以我们只要换掉主板就可以了。至于为什么在类的设计中,我们针对接口编程就可以完成依赖倒置呢?是因为接口的设计需要符合里式替换原则。
里式替换
里式替换即一个软件里面如果把父类都替换成了子类,则它的行为是没有变化的。
比如在设计一个Bird(鸟)类时具有可以飞的属性。同时设计一个Penguin(企鹅)类不可以飞。那么Penguin类可以继承Bird类吗?答案当然是否定的。(因为不符合里式替换的子类可以替换掉父类的原则。)
正是由于子类可替换父类,父类才可以被复用,而子类也可以在父类的基础上增加行为。同时正是因为子类可替换父类,才使得使用了父类的模块在不需要修改的情况下就可以扩展,使开闭原则成为可能。
总结
如果编写程序时考虑的都是依赖抽象编程而不是依赖细节编程,即编写程序的依赖关系都终止于抽象类或者接口则是面向对象的设计了。