在设计模式的江湖中,各种“牛逼”级的人物纷纷登场,你方唱罢我登场,我方唱罢你登场。有的修炼的是“行为型”的外功,有的练得一手“构件型”的内家子,还有的剑走偏锋玩的一套“创建型”的招式。就像所有的江湖一样,在高手如云的地方,总会出现一个高手中的高手,他融汇百家之长,他雄霸江湖,他号令群雄,在武侠中是少林——天下武功出少林。在设计模式的江湖中,他是“六大模式”——天下模式出原则。就像武功一样,招式千变万化,但万变不离其宗,剑谱千奇百怪,终究万剑归宗。今天就说说街巷间传言甚多的“六大原则”。

IOS设计模式反思——六大原则

在设计模式的江湖中,各种“牛逼”级的人物纷纷登场,你方唱罢我登场,我方唱罢你登场。有的修炼的是“行为型”的外功,有的练得一手“构件型”的内家子,还有的剑走偏锋玩的一套“创建型”的招式。就像所有的江湖一样,在高手如云的地方,总会出现一个高手中的高手,他融汇百家之长,他雄霸江湖,他号令群雄,在武侠中是少林——天下武功出少林。在设计模式的江湖中,他是“六大模式”——天下模式出原则。就像武功一样,招式千变万化,但万变不离其宗,剑谱千奇百怪,终究万剑归宗。今天就说说街巷间传言甚多的“六大原则”。

第一章 缘起
是什么
六大原则,是谁名什,师出何门,曾经做出过什么经天纬地的事情?大家众说纷纭,我这里只是说说坊间流传较多的一种说法。
我们先不深究六大原则的细节,先看看他们都长了个什么模样。

单一指责
里氏替换
依赖倒置
接口隔离
迪米特法则
开闭原则
面向对象
据说六大原则和面向对象(Object-Oriented)渊源很深。在某些场合下,人们经常会这样谈起:面向对象的六大原则有什么什么。也就是说六大原则,不是个石猴,凭空就变出来的。他是从面向对象的某些特质中演变而来。

面向对象是编程范式(关于编程范式的东西,看客可以出门左拐《关于程序设计和思维的思考》)的一种,而且是时下最流行的。面向对象其实是我们对于程序的一种理解方式,用“Object”的方式去理解程序。于是很关键的就有两个东西:

对象本身的特征
对象之间的关系
在对这两个东西研究的基础上发展出了面向对象的三个基础特征:封装、继承、多态。仔细看看,就觉得封装是说的怎么去处理对象本身的特质,而继承和多态处理的是对象之间的关系。人们自然就会问了,只知道了这些特征没有一些可以操作的东西怎么成啊。于是六大原则和设计模式来了,指导着面向对象的实践。告诉你一些在处理对象和对象之间的关系的时候,应当注意一些什么,又应当遵守一些什么,或者应当规避些什么。

鸡生蛋,蛋生鸡
原则,故名思议就是本质,是设计模式的起源。他指导着怎么去创造设计模式。这个是比较直白的了。但是,我搜了半天也没有找到一个地方能够明确的说明白,到底是先有的设计模式,人们用着用着发现:唉,应该再抽象一层到原则;还是先有的六大原则,在其指导下有计划有预谋的搞出了设计模式。

但无论是哪一种,都在说明一个问题:设计模式和六大原则之间或许没有那么明显的界限。他们不过是用来处理实际的变成问题的时候的一种思路或者思想而已。只要在使用的过程中,能够很好的解决问题就OK了,何必纠结于疍与鸡的问题。

在其他范式中的应用
既然是一种思路或者思想,他一旦出来后,可能就不局限于应用在面向对象这一种地方了。在其他的一些编程范式中,或许你也能够发现它的一些影子。

第二章 各显神通
概述SOLID
单一指责
定义:就一个类而言,应该仅有一个引起它变化的原因。

解析:从定义来看,理解起来应该不困难,通俗点地说就是不存在多个原因使得一个类发生变化,也就是说一个类只负责一种职责工作,该原则是六大原则中最简单的一种,因此不必多说。

优点:让一个类只负责一种职责的好处有如下几种

(1)类的复杂度降低,一个类只负责一个功能

(2)可读性增强,复杂度降低,阅读起来自然轻松

(3)可维护性强,一个易读、简单的类当然也易维护

里氏替换
定义:里氏替换原则的定义有两种,据说是由麻省理工的一位姓里的女士所提出,因此以其名所命名。

定义1:如果对一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1所定义的程序P中在o1全都替换成o2时,程序的行为不发生任何变化,那么T2为T1的子类。

定义2:所有引用父类的地方都必须能够透明地使用子类对象。

解析:其实两个定义所表达的意思都相同,大概是说,就是在所有父类出现的地方,子类都可以出现,并且将父类对象替换为子类对象的时候,程序不会抛出任何异常或者错误,因此我们需要注意的是,尽量不要重载或者重写父类的方法(抽象方法除外),因为这样可能会改变父类原有的行为。

代码:

? 1 2 3 4 5 6 7 8 9 10 11 class Base{ publc void action{ System.out.println("1+1=2"); } }

public class Client{ public static void main(String[] args){ Base b = new Base(); b.action(); } }

运行结果:1+1=2

? 1 2 3 4 5 6 7 8 9 10 11 12 class Concrete extends Base{ public void action{ System.out.println("1+1=1"); } }

public class Client{ public static void main(String[] args){ Base b = new Concrete(); //将所有父类出现的地方都替换成子类 b.action(); } } 运行结果:1+1=1

由上可见,子类在扩展父类的功能时,重写了父类方法,导致了程序结果的错误。因此,对于里氏替换原则的更通俗的说法就是,子类可以扩展父类的功能,但不改变父类原有的功能。

优点:可扩展性与可维护性强

依赖倒置
定义:抽象不应该依赖于细节,细节依赖于抽象。

解析:依赖倒置原则在程序编码中很常运用,其中心思想就是面向接口编程,高层模块不应该依赖底层模块(原子操作的模块),两者都应该依赖于抽象。接触过Spring框架的朋友都知道,Spring框架就是一个很好的依赖倒置原则思想的体现。

接口隔离
定义:一个类对另一个类的依赖应该建立在最小的接口上。

解析:一个接口代表一个角色,不应该将不同的角色都交给一个接口,这样会导致形成一个臃肿的大接口。听起来好像有些像单一职责原则,但是不尽然,在单一职责原则中,一个接口可能有多个方法,提供给多种不同的调用者所调用,但是它们始终完成同一种功能,因此它们符合单一原则,却不符合接口隔离原则,因为这个接口存在着多种角色,因此可以拆分成更多的子接口,以供不同的调用者所调用。

优点:符合高内聚低耦合的设计思想,意在设计一个短而小的接口和类,这个在代码重构中比较常见,可读性、可扩展性、可维护性等都不错,很受程序员们的欢迎。

迪米特法则
定义:一个对象应该对其他对象有最少的了解。

解析:意思就是一个对象对其他对象知道得越少越好,其核心就是低耦合。迪米特法则又有一个解释,即是只与直接的朋友通信,何谓直接朋友?大家都知道,对象之间的交流必定是少不了耦合的,为了降低对象之间的耦合,我们可以设定一个中间者,让这个中间者给要通信的双方进行传话,这样的话,这两个对象耦合程度可以达到很小,而我所说的这个中间者,就是直接朋友。

优点:我们可以试想一下,两个对象之间的耦合越大,其维护起来就越是困难,假如我们需要改变其中一个对象,另外一个对象也要进行大量的修改,而迪米特法则,则让对象之间的耦合降到最小,符合高内聚低耦合的特性,这样维护起来当然就容易多咯~

开闭原则
定义:一个软件实体(如类、模块、函数)应当对扩展开放,对修改关闭。

解析:该定义理解起来略微抽象,按照自己的理解就是,对于一个已经存在的类,如果我们需要继续去扩充其功能,不应该直接修改该类的内部实现,而是应该通过抽象类或者接口来进行功能的扩充,由此可见,实现开闭原则关键是抽象。至于为什么需要开闭原则,我们可以假想,一个网络游戏若需要更新,我们常做的方法是为该游戏打上一个补丁,或者是更新它仅需更新的模块,而不会把整个游戏卸载,然后再重新装上新版本的游戏。

优点:

(1)具有灵活性,通过拓展一个功能模块即可实现功能的扩充,不需修改内部代码。

(2)具有稳定性,表现在其基本功能类不允许被修改,使得被破坏的程度大大下降。

第三章 重剑无锋,大巧不工
像武侠的世界中,最牛逼的人物,不止是会了什么降龙十八掌之类的绝世武功的主。而是少林寺中的扫地神僧——一无招胜有招。话说,剑术分三级:

手中有剑,心中无剑。此为初作者。虽然手握神兵利器,但是不知如何去用。刚刚知道有六大原则和设计模式这个东西,但是止步于知道,不知如何运用。
手中有剑,心中亦有剑。这是大师,深谙剑谱,也有一把神兵利器。但是容易陷入刻意追求形式的境地。要么一心想苦练《辟邪剑谱》——欲练此功,必先自宫....;要么用剑的时候,一定要按照某种特定的套路去做。这个时候,已经熟谙六大原则和23中常用的设计模式。在设计或者编码的时候,刻意追求应用设计模式。
手中无剑,心中有剑。这是已经做到人剑合一的境地了。其虚手中无剑,其实万物皆剑。一草一木,信手拈来,皆幻化做锋利的兵器。扫地神僧,扫把都是神器。郭靖用的那把剑不是也是看起来很笨重。所谓重剑无锋,大巧不工。
这个时候,在设计或者编码的时候,不在可以的追求设计模式,也不再在乎形式。往往很多时候出来的方案:简单、粗暴、有效。

Last modification:April 7th, 2020 at 08:04 pm
如果觉得我的文章对你有用,请随意赞赏