设计原则学习小结

日期:2015年4月14日 15:43 星期二 农历 乙未 羊年 二月廿六
修改记录:




正文:
事物往往有其内在规律,遵循事物的内在规律有时往往能起到事半功倍的效果。面向对象的软件设计也是这样,要想设计出扩展性好,重用性高的软件,也必须遵守一些它的一些基本原则。按照这些原则的首字母,我们可以简称为"SOLID"原则。


原则一:单一职责原则(Single Responsibility Principle)
类或者函数只有一个引起它变化的原因。
什么是职责:职责就是指变化的原因。
我的思考:
(1)单一职责原则不符合面向对象的理解方式。例如说书中所举的Modem的例子,本身能够很好的从官Modem类来映射现实中真实的Modem类,从职责上把它们分成两个类反而不那么好理解了。
自我解答:个人理解确实存在这个问题。不过这样做能迫使开发人员能从职责的角度去把类进一步细分,也是一个思考的过程,对实现来说是有好处的。
(2)Modem类分成两个类后,最终还是要合一。这样不就永远也有一些类无法满足单一职责了吗?
自我解答:最终对外暴露的肯定还是一个Modem类,但是经过细分以后,需求改变以后,Modem类基本是稳定的。因为需求的改变一般只会改变会话管理与数据管理这两个类中的一个,并不会因此而改变Modem类。所以对三个新的类来说,都实现了单一职责了。


原则二:开放封闭原则(Open-Closed Principle)
类应该对扩展开放,对修改封闭。
我的思考:
(1)有些需求是无法通过扩展来实现,或者说通过扩展来实现的代价是非常大的,这样如何做到开放封闭原则呢?
自我解答:个人理解确实存在这个问题,无论设计得多么完美的软件都可能存在这种问题,只是我们要尽量降低出现这种问题的可能性。用丁辉的话来说,就是:使得软件的设计与需求变化的方向正交,这样需求的变化就不会影响到已有的软件设计了。但是一旦真有这种需求,应该通过进一步的重构来适应新的需求变化的方向。
(2)其实这个开放封闭原则与我们现在商用版本修改代码的策略很类似:新增需求与修改故障尽量不影响现有架构与功能。最常用的办法往往是在某些地方特殊处理一下即可,虽然按照开放封闭原则,我们现在的这种做法应该是修改而不是扩展,但是我们应该是用尽量少的修改来达到扩展的目的,应该算是一种特殊的扩展吧,至少目的上应该是一致的。在C语言的前提下,新增代码100%的不修改原有代码,在目前来说是很难的。但是我们现有的“打补丁”的方式真的好吗?我不知道。但是至少日积月累以后,被后面的人骂的概率很大。那么在现有的条件下,我们应该如何突破开放封闭原则这个魔咒呢?


原则三:里氏替换原则(Liskov Substitution Principle)
所有父类对象出现的地方都应该可以用其子类对象替换而不会产生错误。
我的思考:
(1)里氏替换原则是否要求父类的所有的方法都是虚函数呢?如果不要求,那么父类在调用那个非虚函数方法的时候,子类就不能替换,也就没有遵循里氏替换原则了。我个人认为应该是的。
补充:经过向金华同学请教,金华认为里氏替换原则应该不要求父类所有的函数全都是需函数。当父类在调用某个非虚函数方法的时候,可以把子类的类型强转成父类的类型然后去调用,这个时候能够正常的执行,所以应该是符合里氏替换原则的。那么新的问题来了,里氏替换原则是否要求在替换的时候子类类型都要强转成父类类型呢?金华认为是的。
(2)通过上一个问题,我们得到的结论是不要求父类的所有函数全都是虚函数。那么当父类有一个非虚函数,子类也有一个同名的非虚函数时,这种情况是否满足里氏替换原则呢?从表面上看,类型强转成父类以后,子类的那个非虚函数永远起不到作用,貌似满足里氏替换原则,其实不然,因为替换后的执行结果的表现还是父类的,但是程序员的预期是子类的,与预期不一致,应该不符合里氏替换原则。
(3)我们经常讲子类与父类的关系应该是IS-A的关系,即子类应该是父类的一个更具体的表示。但是并不是具有这样关系的就是满足里氏替换原则的,里氏替换原则必须同时满足前置条件与后置条件。所谓前置条件与后置条件应该是在定义基类的时候就约定好的一个契约。IS-A关系通常只是一个前置条件,后置条件通常是隐含的。例如正方形与长方形的例子,长方形是基类,它的一个隐含的后置条件是修改长不影响宽,修改宽不影响长。如果正方形继承了长方形,那它虽然满足了前置条件,确不满足后置条件。




原则四:接口分离原则(Interface Segregation Principle)
接口应该尽量小而明确,不应该强迫客户依赖与他们不用的方法。
我的思考:
(1)我们产品代码中的DbAccess接口是否是一个胖接口?既然说接口应该尽量小而明确,那么我们是否应该把它按照表来拆分成各个不同的接口呢?我个人认为它不是一个胖接口,因为各个表的行为都是增、删、改,对客户端来说只是表名不同而已,DbAccess应该是一个很好的抽象,它并不会造成各个客户端之间的耦合,所以我理解它应该不是一个胖接口。真正的胖接口应该是让某些客户端看到了一些它不需要的东西。


原则五:依赖倒置原则(Dependency Inversion Principle)
高层模块不应该依赖与底层模块,二者都应该依赖于抽象。具体依赖于抽象,抽象不依赖于具体。
我的思考:
(1)依赖于抽象,抽象是什么?其实抽象就是一堆接口的集合。这个原则应该是所有的设计原则中最容易理解的一个原则,也是最符合我们在实际项目中用得最普遍的一个原则。就是让我们基于接口编程。这就要求我们的接口要设计得尽量的稳定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值