设计模式中常用的几个“套路”

    Gof的设计模式一共有23种模型,这23种模型只能算是一些情景下的通用解法,是离散的而非系统的解决方案,所以在理解、记忆和应用时,如果不是花费足够的时间熟悉和使用这些模型,就难以准确地使用合适的模型或者模型的变体解决开发中的问题。不过还好,这个23种模型中,存在着更加底层的常用套路,能够被提取出来,可以帮助理解和掌握设计模式的精髓。

接口

    接口,毫无疑问是设计模式中最常用的技巧。接口是java中的概念,一般相当于C++中无属性的抽象类。在23中设计模式中大部分都使用了接口,唯一不同的地方是,不同设计模式使用接口的原因可能并不一样。
    接口可以用来作为一种标准规范。在现实中比较类似的例子是工业生产中对于零件的标准,这种一般都会有国家规范。比如一个汽车生产过程中需要某种特定大小的齿轮,但是又丝毫不关心齿轮的生产工艺、材料成分等这种比较细节的实现,这时候只需要从供应商那里买回和设计稿中一样规格的齿轮,汽车能够跑起来即可。如果在使用中发现这种齿轮不好用或者不经济实惠,就可以直接替换另外一种同样规格的齿轮。因为有了齿轮的标准规范,才能使这种替换顺利进行。接口在各种模型中就可以作为一种标准规范。比如在策略模式中,可以为不同的策略定义同一个接口,这样在使用不同策略时,可以做到随时替换。在状态模式中,可以为不同的状态定义同一接口,这样是使用状态类的实例时,可以随时替换不同的状态。在命令模式中,可以为不同的命令定义同一接口,这样在触发命令的逻辑中,不用关心具体命令的类型,可以根据场景替换不同的命令。
    接口的另一个作用是可以用来屏蔽系统的细节。在进行模块设计时,如果暴露过多细节给外部,外部可以使用系统内部具体的类或者任何参数,会使系统和外部耦合增大。如果系统内部逻辑需要更改,比如替换类、修改参数等情况,相应的系统外部也需要修改,这往往会造成不必要的麻烦。接口这时候就可以用来作为屏蔽系统内外的守卫,这种应用最典型的外观模式,抽象工厂模式也是比较类似的套路。对外提供的接口方法,作为内部给外部开放的入口,内部任何逻辑的改变,product的搭配和组装的变化,都不会影响外部系统。另外一个比较特殊的使用是备忘录模式。备忘录模式中为备忘录定义一个窄接口,这样在外部(备忘录管理者,caretaker)就不能访问备忘录的内部数据。而在内部(原发器,originator)定义备忘录为内部类,这样就形成了宽接口,可以访问备忘录内部的数据,从而实现了”外紧内松“的模式。

抽象类

    相对于接口,抽象类在设计模式中发挥的作用就不那么明显。抽象类和接口的主要区别在于,抽象类中可以定义属性,可以实现方法的逻辑,这一概念在java和C++中的定义基本是一致的。由于特性的不同,实际上抽象类能够产生不能够被接口取代的作用。
    抽象类的延迟实现被使用在了工厂方法和模板方法模式中。一般来说,在构建功能和调用流程都比较相似的类时,如果这些类具有一些相同的逻辑,但是在某些流程又存在不同的逻辑实现,就可以使用抽象类的延迟实现,这在一些框架的搭建上应用广泛,比如spring mvc。在工厂方法中,抽象类(父类)的方法中定义了一部分构建的流程,同时调用了抽象方法作为作为模板方法,返回具体的产品。在子类中实现了模板方法,构建了具体的产品。这样既复用父类中通用的代码逻辑,同时也可以使用不同子类区分出不同的产品,充分应用了抽象类延迟实现的特性。模板方法中也使用了抽象类延迟实现的这一特性。在父类中定义一个算法的骨架,将一些步骤延迟到子类中,这样模板方法模式可以使得子类不改变一个算法的结构,即可以重定义该算法的某些特定步骤。
    抽象类的另一个作用是可以实现子类对原有方法逻辑的拓展。在装饰模式中,子类装饰器在运行自己的方法逻辑之前,会使用super.operation方法,先获得父类方法运行之后的结果,然后再运行自己定义的operation方法的逻辑,这样可以实现对父类方法的逻辑的扩充叠加甚至是修改。Windows的MFC框架,窗口类往往具有比较复杂的继承结构,比如一个按钮类CButton也属于窗口类。这样子类在定义自己的代码时,为了兼容父类的逻辑,往往需要先调用父类的方法,然后在父类的方法运行结果的基础上进行拓展。

组合

    组合在设计模式中使用也比较广泛。相比于继承,在类中持有某个对象,从而复用某个类对象的能力,这样会有更好的拓展性。
    组合最常用的功能是代理委托,实现某种形式的解耦。说到代理委托,最典型的非代理模式莫数。在代理模式中,代理类和被代理类需要有一样的方法定义,在内部持有一个被代理类的对象的引用。构建代理类对象需要传入被代理类的对象,当调用代理类的方法时,代理类实际会在内部调用被调用类的方法。实现代理之后,可以做的事情非常多,比如可以在不修改原有的被代理类的基础上,对原有被代理类的方法逻辑进行拓展,可以通过代理类和被代理类的联合实现数据的懒加载,可以屏蔽被代理类的细节,实现与外部系统解耦。这种特性也被应用到了其他的设计模式模型中,比如适配器模式通过代理,将被适配的类和系统的规范进行了统一,算是一个解耦的反向应用。比如迭代器模式,通过组合,访问数据结构内部,实现了对不同数据结构遍历的适配,从而使遍历操作和具体数据结构进行解耦。比如命令模式使用代理,将命令执行方和命令调用方进行解耦。还有中介者模式、访问者模式、解释器模式、备忘录模式中,都可以看到这种功能应用的影子。

    Gof的设计模式中提到的23种设计模式可能只算是应对不同场景的离散模型,而不是系统闭合的完备论证,这中间需要探索的东西还有很多,值得更广泛的思考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章