【设计模式】六大原则之一(单一职责与开闭原则)

来源:互联网 发布:淘宝买家怎么合并订单 编辑:程序博客网 时间:2024/04/28 22:04

【前言】

        最近在学习设计模式,设计模式是面向对象编程的。设计模式有6大原则,而实际上都是互补的,也就是说一些原则需要利用另一些原则来实现自己。下面来简单的介绍一下六大原则其中之二

【单一职责原则】

1、单一职责原则的由来

        初学者在编程的时候可能一开始会有这样的经历,使用一个类来实现很多的功能,新添加的甚至不相关的功能都放在一个类中来实现,煮成了一锅大杂烩,往往使得某个类包罗万象,无所不能。可能刚开始实现的功能比较简单,这样做不会引起很大的问题。但是随着之后项目复杂度的提升,各种不相关的代码耦合在一起,一旦有功能的更改或增删,修改的代码很可能导致其他功能不能正常运行,也就是违背了单一职责原则

2、什么是单一职责原则

        不要存在多于一个导致类变更的原因。通俗的说,就是一个类只负责一项职责

       在软件设计中,秉承着“高内聚,低耦合”的思想,让一个类仅负责一项职责,如果一个类有多于一项的职责,那么就代表这个类耦合性变高了,这些职责耦合在了一起,这是比较脆弱的设计。因为一旦某一项职责发生了改变,需要去更改代码,那么有可能会引起其他职责改变。所谓牵一发而动全身,这显然是我们所不愿意看到的,所以我们会把这个类分拆开来,由两个类来分别维护这两个职责,这样当一个职责发生改变,需要修改时,不会影响到另一个职责。

        单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

3、为什么要用单一职责原则

        说到单一职责原则,很多人都不屑一顾,因为它太简单了,这是常识。在编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的解决方法就是遵循单一职责模式。虽然单一模式如此简单,但是也会有违背这一原则的代码存在。为什么会出现这种现象?因为有职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2

        举例说明,用一个类描述动物呼吸这个场景,代码如下:

       

        运行结果:
        牛呼吸空气
        羊呼吸空气
        猪呼吸空气

        程序上线后,发现问题了,并不是所有的动物都是呼吸空气的,比如鱼就是呼吸水的,修改时如果遵循单一职责原则,需要将Animal类细分为陆生动物类Terrestrial,水生动物Aquatic。我们会发现如果这样修改代码花销是很大的,除了要将原来的类分解之外,还需要修改客户端,而直接修改类Animal来达成目的虽然违背了单一职责原则,但是花销却小很多。代码如下:        
       
        可以看到,这种修改方式要简单的多,但是却存在隐患:有一天需要将鱼分为呼吸淡水的鱼和呼吸还睡的鱼,则又需要修改Animal类的breathe方法,而对原有代码的修改会对调用“猪”“牛”“羊”等相关功能带来风险,也许某一天你会发现程序运行的结果变为“牛呼吸水”了。这种修改方式直接在代码级别上违背了单一职责原则,虽然修改起来最简单,但隐患却是最大的。

4、遵循单一职责原则的优点

(1)降低了类的复杂度。一个类只负责一项职责比负责多项职责要简单得多

(2)提高了代码的可读性。一个类简单了,可读性自然就提高了

(3)提高了系统的可维护性。代码的可读性高了,并且修改一项职责对其他职责影响降低了,可维护性自然就提高了

(4)变更引起的风险变低了。单一职责最大的优点就是修改一个功能,对其他功能的影响显著降低

【开放-封闭原则】

1、什么是开放封闭原则

        开放封闭原则是所有面向对象原则的核心。

        所谓开放封闭原则,软件实体(类、模块、函数等等)应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的

        开放封闭原则主要体现在两个方面:

      (1)对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况

      (2)对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要求对类进行任何修改

2、为什么要用开放-封闭原则 

        对于程序设计而言,如何设计才能面对需求的改变却可以保持相对的稳定,从而可以使得系统可以在第一个版本的基础上不断的推出新的版本呢?答案是在程序设计的时候使用开放封闭原则。但是在设计的时候,绝对对修改的关闭是不可能的,无论模块是多么的封闭,都存在一些无法对之封闭的变化,既然不可以完全的封闭,设计人员必须对他设计的模块应该对哪种变换的封闭做出选择,他必须猜测出最有可能发生变换的种类,然后构造抽象来隔离那些变化

       在我们最初写代码的时候,假设变化不会发生,当变化发生时我们就构造抽象类来隔离变化。当然,不是在什么情况下应对变化都是容易的

       开放封闭原则是面向对象的核心所在,遵循这个原则可以带来面向对象所谓的巨大的好处,也就是可维护、可扩展、可复用、灵活性好。然而,对于应用程序中的每个部分都刻意的抽象同样不是一个好主意,拒绝成熟的抽象和抽象一样重要          

3、如何使用开放封闭原则?

        实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的,而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变故友行为,实现新的扩展方法,所以对于扩展就是开放的

        对于违反这一原则的类,必须通过重构来进行改善。常用于实现的设计模式主要有Template Method模式和Strategy模式。而封装变化,是实现这一原则的重要手段,将经常变化的状态封装为一个类

        以银行业务员为例:

        没有实现开放封闭原则设计的:

       
        这种设计显然是存在问题的,目前设计中就只有存款、取款和转账这三个功能,将来如果业务增加了,比如增加中购基金功能、理财功能等,就必须要修改BankProcess业务类。我们分析上述设计就能发现不能把业务封装在一个类里面,违法单一职责原则,而且有新的需求发生时,必须修改现有代码违反了开放封闭原则
        那么,如何才能实现耦合度和灵活性兼得呢?那就是抽象,将业务功能抽象为接口,当业务员依赖于固定的抽象时,对修改就是封闭的,而通过继承和多态继承,从抽象体中扩展出新的实现,就是对扩展的开放
        下面是符合开放封闭原则的设计:
         
        这样,当业务变更时,只需修改对应的业务实现类就可以了,其他不相干的业务就不必修改了。当业务增加,只需增加业务的实现就可以了

        其实笔者认为,开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。  

       本文只是对基础知识做一个小小的总结,不深究。如有不同,见解欢迎指正

       本文所有代码均已通过作者测试

       本文所有内容均为作者原创,如有转载,请注明出处


0 0
原创粉丝点击