设计模式启示录 (一)

来源:互联网 发布:美丽的红树林 淘宝 编辑:程序博客网 时间:2024/06/05 10:05

设计模式启示录 (一)

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

一)设计模式的含义

  软件设计有两个层面:High Level的架构设计,Detail Level的实现设计。

      1)架构设计:对软件 层次 -> 子系统 ->组件的静态设计,以及它们运行时交互关系的动态设计。特殊业务领域,对分布式和大数据运算开源框架的运用也在架构设计的范畴。架构设计并非本文讨论的重点,仅概念性带过。

 

       2)实现设计:在架构设计的基础上,对架构设计中的每个待编码实现的component予以实现上的设计。这项设计工作,可剖析为两个方面:其一,业务逻辑设计;其二,灵活性设计。其中灵活性设计,目的是为业务需求可能发生的变化做铺路,以便在变化来临时以用比较小的代价完成需求变更。灵活性,是软件设计原则和软件设计模式被提出的动因。接下来,我们重点看一下各种软件设计模式是怎样巧妙的“灵活”的。

 

  不少讲述设计模式的材料,均已小鸭子呱呱叫,小鸡吱吱叫之类所谓形象易懂的案例引入模式。笔者不以为然,形象移动的案例读起来有趣易懂,但是落实到自己的项目,未见得容易带入应用。笔者讲述的设计模式,所有案例均围绕物联网领域的开发需求场景展开,包括多设备,多协议,多平台。需求概要如下图:

 

  后续对设计模式的所有讨论,都围绕上述需求场景展开。话说,follow大师的轨迹不是丢人的事情,笔者虔诚的followGOF几位大师所提出的设计模式们。接下来,笔者带各位进入大师们的设计模式世界。如有砖头,请毫不留情的向笔者拍来~

 

  特别的,虽然面向对象的设计不提倡用module这个词汇,我们后面的讨论中依然使用这个单词,{ module }构成component。如此方便在对设计模式的讨论中,区分一个设计模式运用于“大的component”间,还是“小的module”间。

 

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

 

二)设计模式的核心 - 抽象

        GOF设计模式提出了6条设计原则,和23个设计模式。笔者对GOF提出的原则和模式做了一个重塑性的提炼,如下图:

 

1. 设计之核心:抽象

       23中设计模式涵盖了我们常用的设计需求。尚未与设计模式有过深交的新新程序员,虽然未见得有以模式为专业指导进行代码的设计,但其实很可能在不知不觉以“非正规”的方式应用着模式们。比如Observer模式,比如Singleton模式。所有的设计模式,围绕的中心是一个词:抽象(Abstract)。抽象的目的有二:其一,解耦,其二,复用。设计模式告诉我们的,恰恰将常用的抽象做了总结归纳,并且告诉我们怎样以更好的方式完成这些抽象,以达成解耦和复用之目标。

 

       例如Adapter模式,是将对某类component的调用需求抽象为一组接口,从而达成对具体component依赖的解耦。例如Facade模式,是将某component提供的能力抽象为一组接口,从而达成对具体调用者的解耦。例如Strategy模式,是将module内部特定多变的算法做抽象,从而达成module对具体算法实现的解耦。再如Template模式,是将某个module块所应用的数据类型做抽象,使得module块适用于多种数据类型,从而达成逻辑对具体数据类型的解耦。抽象,是一个设计模式的灵魂,也是程序员们的灵魂~

 

2. 设计模式之分类:以抽象为中心的分类

       GOF将模式按照“创建型模式”,“结构型模式”,“行为行模式”进行划分。这样的划分方式是按照模式对应的设计领域来划分的:创建型模式应用于对象的创建;结构型模式用于component间或者module间交互和衔接的设计;“行为型模式”用于module内部逻辑细节上的一些设计。而笔者的设计模式世界中,一切以抽象为中心,对设计模式的归类亦是按照不同类型的抽象进行。分离详细方式如下:

 

        1)  Interface Abstract分类:囊括对接口抽象的模式,包含AdapterFacadeProxy三种经典的设计模式。

 

        2)  Logic Combine分类:囊括对逻辑块间之整合方式抽象的模式,包含BridgeMediatorCommand三种经典的设计模式。

 

        3)  Logic Extract分类:囊括对某多变逻辑块分离方法抽象的模式,包含StrategyVisitorIterator三种经典的设计模式。

 

        4)  Create Objects分类:囊括了各种对象创建之抽象的模式,包含Abstract FactoryFactory MethodBuilderPrototypeSingleton几种经典的设计模式。

 

        5)  Event Notify分类:囊括了逻辑块间通知的模式,包含ObserverResponsibility Chain两种经典的设计模式。

 

        6) Logic Reuse分类:包含了Template这样一种对数据类型做抽象和解耦的设计模式。

 

        7) Logic Models分类:囊括了一些特定逻辑场景下应用的设计模式们,包含CompositeDecoratorStateInterpreterMemonto几种经典的设计模式。

 

如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

 

三)七类设计模式

        接下来我们进一步讨论前章提及的七个设计模式分类,看一下每类设计模式分别是为了解决什么样的问题,以及能达成什么样的效果。在下一篇文章中,我们会详细的对具体的设计模式展开讨论。

       1) Interface Abstract分类:

         A)  Before

 

             问题描述:

           图示中的Component A直接调用Component BInterface。以下两种情况:一,随着软件需求变化,如果Component B的能力无法满足Component A的需求了,那么Component A需要针对新使用的Component C重新编程;二,Component A需要Component B提供简洁易用的接口,但是如果Component B仅仅提供Component A所需的简单接口,又会降低Component B的通用度和接口调用的灵活性。

             以上所述问题对应的典型编码场景,诸如我们代码中对Windows/Linux平台的Socket/Thread接口的调用,或者对某个第三方库的调用。

 

        B)  After

 

    设计效果:

              Component A调用Component B的角度看,Component AComponent B的需求抽象为一组Interface API。这样在Component B需要被替换时,仅需对新使用的Component C基于Interface API做一层封装即可实现切换。

    从Component BComponent A调用的角度看,Component B呈献给Component A的接口被封装为一组简单适用的Interface API。同样的,Component B呈献给其它调用者的接口,也可以被封装为另一组简单适用的Interface API。由此避免了Component B的实现受制于各个调用者。

 

       2) Logic Combine分类:

       A)  Before

 

           问题描述:

           不同内容的逻辑Module被杂糅于一起,或者不同功能Module虽然被分离出来了,但是彼此间直接的互相调用,功能Module间严重耦合。

 

         B)  After

 

    设计效果:

    图示的设计中,用一个专门的Mediator来协调各个Module之间的调用关系。这样各个module是相对解耦的。如果某个Module内部实现发生变化,仅需孤立的调整发生变更的Module,而避免操心对其它Module调用的随之调整。

 

        3) Logic Extract分类:

        A)  Before


 

                问题描述:

                一子功能模块,有多个实现版本。最简单的处理方法,在Module内部直接实现此块子功能的多个版本,每个版本对应一组不同的接口,按需通过宏定义或者一系列if else来决定所调用的版本。此种方式的弊端:其一,子功能深植于具体业务Module内部,通用度较差;其二,如果有新功能版本加入又需要到处更改if else

 

        B)  After

 

    设计效果:

              将子功能提供的能力抽象为Abstract接口,Module仅依赖抽象的接口。这样的好处,其一,只需指定Module所使用子功能版本的具体实现类,即可切换Module所用的子功能版本;其二,大大提升了子功能各个版本的通用度,尤其是如果此子功能是一个算法,这样的处理是颇具意义的。

 

        4) Create Objects分类:

         A)  Before

 

              问题描述:

          面向对象设计强调依赖于抽象,而不去依赖具体实现,也就是应对基于抽象接口编程(依赖倒置)。但是无论怎样抽象,有一块内容是避无可避的要基于具体的实现类来编程,这就是对象的创建。如果对象的使用者,内部直接的去撰写对象的创建逻辑,那么对象一旦发生变化,使用者要随之发生调整。

 

        B)  After

 

    设计效果:

    将对象的创建或着隔离起来,或者抽象为Abstract接口。调用者仅依赖创建对象的“Objects Creation Impl”,或者依赖抽象的Creation方法。这样具体的对象发生变更时,仅需调整“Objects Creation Impl”,或者调整Creation方法具体实现即可。避免了在此种情况下去改动调用者。

 

        5) Event Notify分类:

        A)  Before

              N/A

              问题描述:

              N/A

        B)  After

 


    设计效果:

              事件通知有两类经典逻辑模型:观察者,责任链。前者用于在某事件发生时,通知到所有事件的注册者。后者用于在某事件发生时,通知给相关责任链,责任链中会传递该事件直至找到一个合适的处理者。这两种模型相比大家都是熟悉而且常常在用的,只不过我们回头来看GOF设计模式对此的描述,可以完美化我们对此的使用方法。

 

        6) Logic Reuse分类

        A)  Before

               N/A

               问题描述:

               容器,算法,这些都面临着多数据类型。如果没有模板方法,最糟糕的状况下,我们需要针对每个数据类型分别实现一遍容器,算法。Copy past,修修改改,这显然是程序员最不愿意做的事情。(实际也是常常做的事情)

 

        B)  After

 

    设计效果:

              设计实现对类型“通用”的模板容器,模板算法。调用者需要某个特定数据类型的容器或者算法时,可以动态的按需去具体化模板容器和模板算法。C++template最先支持了这样的设计方法。Java现在也实现了和C++template极为相似的模板机制。

 

        7) Logic Models分类:

        A)  Before

               N/A

               问题描述:

               N/A

        B)  After

 

     设计效果:

                  这几种特定逻辑场景所需的设计模式,我们放到后面的篇章去做具体的讨论。这里仅仅予以列举。

 

  以上,是对GOF设计模式核心和分类的概要讨论,在后面的篇章中,将会详细的介绍23中设计模式。

  如需转载请注明出处:http://blog.csdn.net/qingyixiaoxia  微信号:qingyixiaoxia

原创粉丝点击