喵星之旅-沉睡的猫咪-面向对象的设计原则

一、设计原则是什么?

有句话叫“人民群众是历史的创造者”,他的意思我理解为任何的理论都是基于具体的客观展现总结出来的,没有人民创造的既定事实,就无法出现任何的有理有据的理论模型。

对于面向对象的软件设计,最著名的一本书就应该是当年gof的那一本《设计模式:可复用面向对象软件的基础》。设计模式是面对具体问题,进行抽象分类,然后总结出来的行之有效的解决方案,就像人去创造历史。设计原则是进一步研究这些解决方案,进一步抽象出的指导思想。

如果把设计模式比喻成传统数学,即“1+1=2”的那套理论,那么设计原则就是现代数学,也就是“1+1=1”的这样子的抽象数学理论。当然,现代数学中这个结果不限于1,只要是符合规则的都可以成立,感兴趣的可以去学习一下“抽象代数”这一课程。

二、设计原则的特点?

因为是指导思想,所以任何的具体代码都无法完美诠释一个设计原则,因为他应当是抽象的,足够的抽象。只有具体到解决方案,与之配套的设计模式才有可以参考的具体代码实现,当然是仅限于参考。

设计原则是超越语言的。这一点很明显,因为设计模式都是超越语言范围的,不限于java或者c++,只要是面向对象的语言都是适用的。如果我们将他进一步抽象,还可以用到编程语言之外,指导我们管理项目、人员,甚至是影响我们的生活,因为它是思想。

思想是非常强大的武器。

三、设计原则有哪些?

设计原则到底有多少,无人统计过,而且也无法统计。一般提的是六大设计原则,当然设计原则不止这些,有大必有小,显然还有很多小设计原则。

六大设计原则是什么?我们去查阅资料的话会发现,说法不一,如果把比较常见、支持率较高的说法拿出来,会有2套,一共7个设计原则,所以也可以称之为七大设计原则。前五个设计原则是一致的:开闭原则、里氏替换原则、迪米特法则、接口隔离原则、依赖倒转原则,对于最后一种设计原则有2个支持较高的说法:合成复用原则、单一职责。

讲设计原则的一大乐趣就是每次都带着学生数六大设计原则:1、2、3、4、4、5、6,你看6个齐了。要不再数一边1、2、3、4、5、6、6,艾~怎么数都是6个。

四、如何学习设计原则?

首先要先了解设计模式,如果没有长期的积累,根本无法理解设计原则。设计原则是我们具体实现的方法高度抽象,所以要有基础。

就像2020年初,某汤老师将一种新的授课方式带到了课堂,结果大受打击。对于其授课的改变到底是好还是不好,本人不作评论。我们要看的是为什么大受打击,因为很多人不买账,这就要看其进一步的原因。简单来说就是这个方式是空降的,不曾走到群众中去,然后直接实行方案,必然造成困难。假设这种授课方式非常好,但是没有群众基础也是非常困难。应该要深入到群众中去,然后在根据客观情况进行分析,提出相应的理论,进而实行,实行前要让群众就参与进来。所以,在学习设计原则之前最好已经很了解十种以上的设计模式。

设计原则和设计模式就像思想和知识积累。当年65岁的丘吉尔能够让英国最后走上胜利之路不是因为他的出现让英国飞机更多了、让德国军队变少了、让英国的炮弹威力更猛了。而是他带给了全英国人必胜的决心和永不屈服的斗志。但是如果他直接就是首相,不曾有过其他经历,他是很难带领英国走上胜利的,在首相之前他曾是海军大臣、陆军大臣、空军大臣、军需大臣、殖民地大臣、财政大臣,而且去过保守党、自由党,深入接触过工党,甚至在战斗一线战斗过,当过战俘,就是这些让他了解了全国的情况,才让他有信心带领英国。我们学设计原则就像要去当首相的丘吉尔,想要成功是要积累的,我们要去做海军大臣、陆军大臣、空军大臣等,然后才能做首相,这些大臣的名字就叫设计模式。

五、常见的设计原则细说

1、 开闭原则

简单的一句话是:程序应当是对修改关闭、对扩展开放。

如果你用了飘柔的洗发水,你应该会经常用到这一原则。因为,“用飘柔就是这么自信”。一个实现只应该因错误而修改,新的或者改变的特性应该通过新建的方式实现。如果我们认为类是最小单元,我们是面向类来编程的,那么就不存在被修改的类;如果我们是面向接口编程的,就不应该有被修改的接口;如果是面向方法,就是方法内容不会被改变。想要改变只能创建新的,新的类、新的接口、新的方法(可以是重写)。但是如何定义“修改”、“扩展”,并无严格要求,只要是基于这种想法的实现都是符合开闭原则的。

2、 里氏替换原则

父类出现的地方,如果直接换成子类,程序将没有变化,不受影响。

在java里面其实就是继承的规则。如果继承就是里氏替换原则,那何谈遵守这一规则呢?这是因为设计原则不是针对java的,是针对面向对象的,设计一门语言之前就应当去参考这些原则。

有一种说法认为里氏替换原则对继承进行了规则上的约束,比如:子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。这个可以认为有也可以认为没有。取决于我们对变化的认识,没有定义何为“变化”、“影响”的前提下讨论对与错是没有意义的。在java中,如果一个子类替换父类的位置,语法不报错,能执行完流程,我们认为程序没有变化,都是正确的程序,那我们可以认为这是符合原则的。

但是,如果我们认为子类在某些情况下的执行结果,虽然可以执行,但是要进一步判断结果来确认是否发生变化,那么想要符合这一原则,单独的java继承规则的确是不够的,需要添加额外支持。

而本人更倾向于java的继承规则就是里氏替换原则的实现。仁者见仁智者见智。

3、 迪米特法则

有句话叫“你知道的太多了”,这就是不符合这一原则的体现。迪米特法则也叫最少知道原则。也有人称之为“不要和陌生人说话”。

这本身就是一种分层的思想,或者向前后端分离的思想。

4、 接口隔离原则

能用多个接口尽量用多个,不要吧一个类的公共方法都放到一个接口里。这个设计模式倒是一般可以对应具体的实现,因为从名字来说就太具体了,已经确认为接口这一范畴了。因为接口是public的(至少曾经是,这几天发现变了,但是其内容是对外公开的这一想法是不变的),设计到了很多的权限问题,也叫边界。很多的设计原则也是围绕着对象的边界展开的。当我们考虑到安全性的时候时需要把一个类的方法放到不同的接口中让外界访问的。

5、 依赖倒转原则

面对抽象而非具体。java中可以简单的理解为面向接口编程。但是也不尽然,这取决于“抽象”是什么意思。目前是建立在接口是抽象的这一前提下。如果某一天我们普遍认为接口就是很具体啊,那时候依赖倒转原则将和使用接口没有任何关系。思想和实现没有必然的对应,善于使用抽象就是这一原则的核心。当你做的事情你认为那是抽象的,就是在使用这样的设计原则,无论别人怎么看。

6、 合成复用原则

尽量少用继承。因为有句话“不识庐山真面目,只缘身在此山中”,这就是有了一定的连带关系,必然会受到一定的牵连。无论是继承还是接口都是创建了关联,那么要变化就需要考虑很多因素。从目前市场上外包的比重之大,就可以看出来合成复用是很值得借鉴的。外包模式就是一种合成复用。想要实现一个功能,不要尝试与之建立关联,只要把他请过来,让他来做就好。淘宝网从php编程java的实现方式也是合成复用的体现。我需要熟悉java的人,难道要把自己的人送到sun去学习?no!直接去sun公司找人就可以了。他的人员变化永远与我无关,而且我的任何变化,也不影响他的人,这就是合成复用的好处。

7、 单一职责

一个类、或者接口、或者什么,如果承担的某些功能,要么应该把功能细化,和接口隔离的意思差不多,但是不限于接口。可能更多的更倾向于类。

六、如何识别设计原则的存在

根本无法识别。

设计原则本身是一种想法,不是具体的实现。一千个读者就有一千个哈姆雷特。对于相同的一段代码实现,到底当事人是抱着怎样的想法来做的,他人无法知晓。但是我们每个人又可以认同具体的实现,然后带上我们自己的想法。这样,对一同一段代码我们就会有不同的解释,就像古诗都有多种解读,这种做法即对有不对。不对是因为和原作者可能有出入,对是因为我们也可以有自己的见解,思想是不应被局限的。

比如:一个类有10个方法,分别被分散到6个接口中去,那么这样的实现是什么设计原则的成果?

我们可以认为是接口隔离,因为实在是太明显了。

我们有时候也可以认为是开闭原则。因为我们从不知道这个结果是如果产生的。比如最开始是一个类、一个接口,里面都是2个方法。后来接口一个一个的增加,到了3个接口,7个方法。然后4接口、8方法。最后6接口10个方法。很明显了吧?是开闭原则。

但是这是接口啊,不就是抽象的么,难道不是依赖倒转,当然是。

分散到不同接口到底原因何在?是不是认为一个接口内的功能已经是相对完整,不同的功能不应该放在一起。那岂不是单一职责?当然是!

单一职责出来了,有没有想是不是迪米特法则?谁说不可以。

那么问题来了,它到底是什么设计原则?谁都不知道,只有当初写的那个人知道。如果是多个人在不同的环境写出来几乎一样的结果,那么他们的设计原则恐怕是不同的。

设计原则更像是一种风格,每个人有各自的习惯,最后再重复那一句话:

一千个读者就有一千个哈姆雷特。

文章目录
  1. 一、设计原则是什么?
  2. 二、设计原则的特点?
  3. 三、设计原则有哪些?
  4. 四、如何学习设计原则?
  5. 五、常见的设计原则细说
    1. 1、 开闭原则
    2. 2、 里氏替换原则
    3. 3、 迪米特法则
    4. 4、 接口隔离原则
    5. 5、 依赖倒转原则
    6. 6、 合成复用原则
    7. 7、 单一职责
  6. 六、如何识别设计原则的存在
|