设计模式——01 策略模式

1 Strategy Pattern(策略模式)

1.1设计原则一

         下面举个例子说明这个原则。

1)案例分析一:

         REQ1假设当前Vander要设计一款游戏,这个游戏里面有许许多多的鸭子,鸭子会呱呱叫,并且会游泳。

解决方法1:Vander 就开始设计了,下面的UML图是他的设计:

         REQ2:需要让鸭子具有飞行的特性,并且不是所有的鸭子都是呱呱叫的,橡皮鸭是叽叽叫的。

解决方法2(在基类加入新方法解决):

Vander就在Duck的基类上,加上了fly()方法,结果发现,所有继承Duck的鸭子都具有飞行的特性了,但是有些鸭子是不会飞的,所以要在所有不会飞的子类鸭子中重写fly()方法;并且为了满足橡皮鸭的需要,在橡皮鸭的这个类中重写了quack()方法,改成了quack(){//叽叽叫},这样每次有新的鸭子不同的叫法的时候都得覆盖一次。显然这种设计是不合理的。

         解决方法3(使用接口解决):

   

Vander将基类中的fly方法和quack方法抽取出来,因为这两个方法比较多变,所以以接口的形式抽出来,然后让需要用到fly方法的实现Flyable接口,同理,Quackable也是这么个原理。但是问题又来了,现在有几十只鸭子飞行的方式都是“用翅膀飞”,难道在这几十只鸭子的实现类中都要对fly(){//用翅膀飞}实现一次吗?显然,解决方法3也有个严重的问题,就是现在的代码无法复用了。

但是根据以上的思路,大概能得出一个设计原则了:

设计原则一:找出应用中可能需要变化的地方,将它们独立出来,不要和那些不需要变化的代码混在一起。

可能刚开始并不知道哪些需要变化,在进行过程中可以将要变化的部分抽取出来,但是问题是像方法3这样抽出来,又无法实现代码的复用。那应该怎么办呢???

1.2 设计原则二

Vander将飞行的接口定义成了一种行为,然后让不同的类去实现这种行为,这样就能让飞行的行为和叫的行为复用到其他鸭子中去了。而且上面是基于接口编程的,调用起来非常方便。

解决方法4-1:

         下面简单说明一下针对接口编程的好处(相较于针对实现编程)

针对接口编程调用起来,调用者都不需要关心具体的实现,假设现在要让猫发出声音,首先先从动物工厂获得猫的实现,然后直接调用animal的makesound()即可。

Animal animal =animalFactory.getCat();

animal.makesound();

但是如果是基于实现编程的话,调用者还需要关心应该调用meow方法,而不是调用bark方法,这就需要关心到具体动物的具体叫法了。

Cat cat =animalFactory.getCat();

cat.meow();

设计原则二:针对接口编程而不是针对实现编程。

1.3 设计原则三

         方法4中将这些行为都对象话,之后就是怎么复用的问题了,接下来需要将这些行为装配给对应的鸭子,甚至可以动态设定行为。

         解决方法4-2:

那么这些行为怎么传入子类的鸭子里面呢,一种是通过构造方法设置进去,另一种是通过set方法set进去,显然是第二种方法比较好了。

         最后我们来考察一下这种设计的可扩展性吧,假设现在橡皮鸭也会飞了,但是橡皮鸭飞行的方式需要依靠火箭来推动,那么现在要如何设计呢?

         首先我们先写一个类实现FlyBehavior接口,然后将这个飞行的行为set进橡皮鸭中去,是不是很简单。我们从这个设计可以推出,这种将行为装配进来的方式非常好用,Spring其实就用了这个策略。

         设计原则三:多用组合,少用继承。

        

现在我们总结一下。

面向对象基础

         抽象、封装、多态、继承

三大原则

设计原则一:封装变化

设计原则二:针对接口编程,不针对实现编程。

         设计原则三:多用组合,少用继承。

模式

策略模式:在上面的行为中,将行为想象成算法,我们定义了许多的行为,这些行为就是一个算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

最后献上此次设计的源码,有需要的小伙伴可以下载来运行一下,首先先自己进行设计,然后再参考,这样才能加深这三个原则的理解。



猜你喜欢

转载自blog.csdn.net/Vander1991/article/details/79889636
今日推荐