设计模式六大原则笔记拾遗
摘要:
开闭原则是面向对象设计中“可复用设计”的基石原则,是面向对象设计中最重要的原则之一,属于“易筋经”级别的。开放扩展,则意味着当有新的或变化的需求时,可以通过对现有代码的拓展来实现,而不需要该变原有程序的结构与内容;封闭修改,指的是程序设计一旦完成,其预定功能即按照既定独立工作,再不可对其做修改操作
『Single Responsibility Principle』单一职责原则
单一职责原则的核心精神是:一个类,或者一个接口,最好只做一件或者一类事儿,当事情发生变化时,它只能受到单一的影响;因为如果职责过多,可能引起变化的原因将会很多,这样就会导致职责和功能上的依赖,将会影响其内聚性和耦合度,混乱由此而生。
单一职责原则在现实生活中早已实践于现代公司制度与工业生产上,像公司的各个部门之间职责分明相互独立,生产流水线的某一环节只需关注拧螺丝,而另一环节只做零件组装等等;遵守这一原则,将使庞大的系统组合起来还能井井有条,即使某个部门、某个环节出了问题或需要改动,我们只需去动那个要变动的地方即可,从而避免因职责功能划分不明而导致不必要的的混乱。同样,程序代码的设计也是如此,功能和职责单一化也是衡量设计优良的一个标准;交杂不清的职责和功能将使得代码从业务逻辑上看起来特别别混乱,别扭且一发而动全身,更糟糕的是在日后的维护中我们可能要花更多的时间,并且这地方的变动极其容易引起让人头痛的BUG,整个系统将面临花费更多精力,承担更多风险!
在代码工程的实施中,遵循单一职责原则将会带来诸多好处:类的复杂性将降低,简单明了的代码将使可读性将大大提高,可维护性自然而然提高,这也预示着因变更引起的风险会大大降低,最重要的是这些好处将会使我们的工作相对轻松愉悦、思路清晰、远离脑爆头大……专注即高效,单一既轻松,人事皆如此。
『Liskov Substitution Principle』里氏替换原则
里氏替换原则的核心精神是:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类;这一精神其实是对继承机制约束规范的体现。在父类和子类的具体实现中,严格控制继承层次中的关系特征,以保证用子类替换基类时,程序行为不发生问题,且能正常进行下去。
里氏替换原则主要发力点是继承基础上的抽象和多态,具体就是子类必须实现父类的方法,是重写;这里要注意是重写(Override)而不是重载(Overload),即保证继承方法的参数和返回数据范围一致!严格的重写,会避免字符类替换时业务逻辑出现问题。
里氏替换原则是关于继承机制的设计原则,违反里氏替换原则将会使继承变的相对凌乱;而遵循里氏替换原则能够保证系统具有良好的一致性和拓展性,我们可以随时根据需要增改不同的子类,这将大大增强程序的健壮性,功能版本的升级可以做到无缝的兼容;而在程序中不同的子类对应着不同的业务,使用父类定义参数,使用不同子类可以轮番上阵,灵活又强大!
*在此重温【重写与重载】
多态性是面向对象编程的一种特性,和方法本身无关。
方法的重载,就是同样的一个方法能够根据输入数据的不同,做出不同的处理——有不同的参数列表,甚至不同的返回值(静态多态性)
方法的重写,是子类继承自父类的相同方法,输入参数一样,但要做出有别于父类的操作,要覆盖父类方法。——相同参数,相同返回值,不同实现(动态多态性)
『Interface Segregation Principle』接口隔离原则
接口隔离原则的核心精神是:尽量使用多个专门的单一的小接口,避免庞大的总接口;专业点的说法是类间的依赖关系尽量建立在最小的接口上。接口业务范围尽可能的小,但是这个小也不能说是说一个接口一个方法,只要不违背单一职责原则即可;接口应该严格体现内聚性,尽可能的浓缩public方法,在开发中避免让功能繁琐的接口巨兽出现;一个类对另一个类的依赖应该建立在最小接口的原则上,避免冗余和无关业务,否则就可能会造成接口污染。遵循接口隔离原则将使接口有效的将细节和抽象隔离,也是在强调接口的单一性,体现抽象编程的特点。大接口因强制要求实现类完成它所有的并非必须的方法、属性等,从而造成设计上的浪费,必然会对后边的维护和改动带来困惑。
但在现实中,如何把握接口越小越好的度,这个很难界定,颗粒度小固然灵活,但过于零碎也会造成结构的复杂化,以下有几个把握规则可以参考:一个接口只服务于一个子模块或业务逻辑;通过业务逻辑压缩接口中的public方法,让接口看起来相对简洁;已经被污染了的接口,尽量修改,如果变更风险太大,则用适配器模式进行转化处理;根据具体的业务去拆分逻辑,然后控制设计思路。
具体如何实施接口隔离,主要有两种方法:1、业务分离,通过增加一个新的接口类型来委托客户的请求,隔离客户和接口的直接依赖,注意这同时也会增加系统的开销;2多重继承分离,通过接口的多重继承来实现客户的需求,这种方式相对较好。具体的使用,视情况而定。
怎么准确的实践接口隔离原则呢?有一本书上写得非常好:实践、经验和领悟。
『Low Of Demeter』迪米特法则
迪米特法则也叫做最少知识原则,其核心精神是:不和陌生人说话,通俗之意是一个对象对自己需要耦合关联调用的类应该知道的更少。这样会导致类之间的耦合度降低,每个类都尽量减少对其他类的依赖,因此,这也很容易使得系统的功能模块相互独立,之间不存在很强的依赖关系。
迪米特法则很纯情、比较保守,不希望和其他的类建立直接的接触;如果真的需要交互关系,也是希望通过自己比较熟的中间类来传达信息。因此,在迪米特法则的实际应用中可能会导致大量的中介类。
迪米特法则的核心就是解耦,弱耦合能使类的复用率提高,在实际中这个解耦是有限度的解耦,不能因法则而法则,应权衡利弊而为之。
『Open Close Principle』开闭原则
开放封闭原则,简称开闭原则。开闭原则是面向对象设计中“可复用设计”的基石原则,是面向对象设计中最重要的原则之一,属于“易筋经”级别的,诸如里氏替换啦,接口隔离啦、依赖倒置啦,都可以看做是开闭原则的实现;在面向对象设计中,抽象类和接口,即是因开闭而生,应开闭而存!
开闭开闭,开放封闭。开放的是拓展,封闭的是修改,即降低耦合,封装变化的集中展现。开放扩展,则意味着当有新的或变化的需求时,可以通过对现有代码的拓展来实现,而不需要该变原有程序的结构与内容;封闭修改,指的是程序设计一旦完成,其预定功能即按照既定独立工作,再不可对其做修改操作(这点很重要!)开闭原则的核心思想就是抽象编程,而不是对具体,因为抽象是相对稳定的,再说了我们还有接口(好多地方接口和抽象类都放一块儿说了)。让类依赖于固定的抽象对象,即可以达到封闭修改的目的;而通过面向对象的继承和多态机制,又可以实现对抽象类的继承,通过复写其方法来改变固有的行为操作,也可以实现新的拓展方法,即可以达到开放的目的。
归根究底,开闭原则就是“万变不离其宗”;变,即变的是需求,宗,既是系统基础核心业务;开放封闭,既可以通过开放拓展满足需求的变化,又可以通过封装而使系统稳定。开闭原则,实乃程序设计心法。
『Dependence Inversion Principle』依赖倒置原则
依赖倒置原则,重要的三层含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。其核心思想是:依赖抽象。
关于“倒置”这个词。准确的讲,这是因为传统的软件开发方法,如结构化的分析和设计,倾向于创建高层模块依赖于低层模块、抽象依赖于具体的软件结构。在实际上,这些方法的目标之一就是去定义描述上层模块如何调用低层模块的子程序层次结构。所以,相对于传统的过程化的方法通常所产生的那种依赖结构,一个设计良好的面向对象的程序中的依赖结构就是“被倒置”的。
在程序的实现中,依赖关系一定会存在于类与类、模块与模块之间。当两个模块之间存在紧密的耦合关系时,最好的方法就是做分离并接口实现:在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。抽象的稳定性决定了系统的稳定性,因为抽象是不变的;依赖倒置原则的运用还可以减少并行开发引起的风险,提高代码的可读性和维护性。依赖于抽象是面向对象设计的精髓,也是依赖倒置原则的核心。
依赖倒置原则是面向对象架构优秀的根本。合理地利用对于建立可复用的框架是必要的,且使程序具有一定弹性。而且,由于抽象和具体相互完全分离,代码的维护就容易很多了。依赖于抽象是一个通用的原则,而某些时候依赖于细节则是在所难免的,必须权衡在抽象和具体之间,所有方法原则都不是一成不变的,技术只是一种业务关系实现的工具,取舍自知。