调侃《HeadFirst设计模式》之策略模式

来源:互联网 发布:阿里网站域名如何解析 编辑:程序博客网 时间:2024/05/01 09:54

             近日阅读著名的《Head First 设计模式》,深深被作者生动风趣的讲解风格打动。作者让看似高深的设计模式变得像游戏一样好玩,这也是一种非常高效的传授知识的方式。介于对作者所讲的每一章都感觉回味无穷,心里有种冲动将回味转化为白纸黑字,供自己回味同时,也希望起到抛砖引玉之用~~~(原书作者不要投诉我。。)

        今天首个要回味的是策略模式,先不管这个名字,咱先讲故事~~

      你是某游戏公司的软件工程师Joe,现在有个打鸭子的游戏要做,因为鸭子种类很多(假如确实非常多,包括假的鸭子),你这样定义鸭子类:

     

  当你做好了这些类以后,产品经理有一天对你说,现在要为每种鸭子添加飞的功能。你觉得作为一个OO软件开发的人来说太easy了,于是你用继承在Duck添加了fly方法如下:

       

       正当你为自己的速度感到相当有成就感的时候,产品经理黑着脸过来,“为什么橡皮鸭子也会飞啊!”。。

       原因很简单,所有的类都继承Duck的fly方法嘛~~使用继承的方式会牵一发而动全身,使得不该用这种方法的鸭子也被强制添加上了这种方法。

      但聪明的你很快想到了面向对象的方法覆盖,把不会飞的鸭子的fly方法覆盖为空不就得了。

      但是产品经理又一次黑着脸。。“如果以后添加很多鸭子,有些不会飞,有些不会叫,有些都不会,你倒一个个给我改试试看!?”。。。

      这时你意识到,需要一个更清晰的方法让鸭子指定可以飞或者可以叫。

      不是有接口么?让会飞的实现飞的接口,会叫的实现叫的接口不就行了?

     

     这时黑着脸的产品经理再次出现。。“你这样重复代码不得很多么?!以后要改某些鸭子的飞行行为不是得一个个改?!”。。

    此时你意识到如果能有一种建立软件的方法,好让我们可以用一种对既有的代码影响最小的方式来修改软件该有多好。我们就可以花较少时间重做代码,而多让程序去做更酷的事……这个世界那该美好许多啊。

    于是你去深山中拜访大师,大师就吐了一句话:“找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。”。。

    大师一语惊醒梦中人,于是你很快想到:为了要分开“变化和不会变化的部分”,我们准备建立两组类(完全远离Duck类),一个是“fly”相关的,一个是“quack”相关的,每一组类将实现各自的动作。比方说,我们可能有一个类实现“呱呱叫”,另一个类实现“吱吱叫”,还有一个类实现“安静”。我们知道Duck类内的fly()和quack()会随着鸭子的不同而改变。为了要把这两个行为从Duck类中分开,我们将把它们从Duck类中取出来,建立一组新类来代表每个行为。

       那如何设计那组实现飞行和呱呱叫的行为的类呢?你想不懂,于是打了个电话给山林中的大师,深沉的大师又只说了一句:针对接口编程,而不是针对实现编程。“。。

       你果然聪明人,一点就破,立刻想出如下方法:

       从现在开始,鸭子的行为将被放在分开的类中,此类专门提供某行为接口的实现。
这样,鸭子类就不再需要知道行为的实现细节。
在新设计中,鸭子的子类将使用接口(FlyBehavior与QuackBehavior)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中。像这样:

      
      像这样各种飞和叫的行为可以被各种对象复用和具体鸭子没关系啦。
     但是每次鸭子定义行为的时候,不是要定义一个对应的类的引用例如flyWithWings去指向flyWithWings对象。这时黑着脸的XX再次出现了。。“大师的话你就理解了一半,难道你没学javad的多态么?!”。。

    其实“针对接口编程”真正的意思是“针对超类型(supertype)编程”。这里所谓的“接口”有多个含义,接口是一个“概念”,也是一种Java的interface构造。你可以在不涉及JavaAinterface的情况下,“针对接口编程”,关键就在多态。利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。“针对超类型编程”这句话,可以更明确地说成“变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时的真正对象类型!”
      你有很快懂了。你这么做:
      
   于是鸭子类就可以这样定义:
   
       根据以上分析,于是你一鼓作气写出如下代码:
                基类Duck:
            
       两个行为接口:
      
     
       飞行具体实现类:
             
    叫的实现类:
        
    运行代码的测试类:
        
      
    GO!!
    结果:
    
   在鸭子里建立了一堆动态的功能没有用到,就太可惜了!当然,最爽的是你可以在运行的时候设定鸭子的行为:
   
   
  
    
  你看,可以在运行时随时设定行为了吧。你真是淫才!


   故事讲到这,该总结下:
         策略模式定义了一系列的算法(鸭子的飞和叫),并将每一个算法封装起来(定义飞和叫的接口,再定义具体的飞和叫的实现类),而且使它们还可以相互替换(随时设定行为)。策略模式让算法独立于使用它的客户而独立变化。在本例中,通过定义出“飞和叫”的接口,从而衍生出多种“飞和叫”的实现类,行为和具体的鸭子没有绑定死,鸭子可以选择不同的行为而不用修改鸭子的方法。当行为发生改变时只要修改行为实现类即可,不用修改鸭子的代码。具体的鸭子类代码量很少,当引入新的鸭子类的时候,只是接收的行为不同而已。而且可以在运行时(main方法)去任意设定行为。这样增加了程序的灵活度和可扩展性。


0 0
原创粉丝点击