码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式 之 策略模式

时间:2016-01-09 18:32:14      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:

设想有一个游戏,游戏中有各种鸭子,它们可以飞,也可以呱呱叫。这样一个游戏该怎样设计呢?

一、使用继承:

鸭子虽然有不同的种类,但是也有一定的相同之处,所以我们可以从鸭子中提取一个父类Duck,让不同种类的鸭子类继承自父类,将所有鸭子共有的属性和行为放到父类中。

这样做看似没有错误,但实际上存在以下两个方面的错误:

1、子类的可用行为可能远大于我们的期待范围。把所有方法和属性都定义在Duck父类中,再由所有子类去继承这个父类,那么所有的子类就都具备父类的方法和属性。就拿这个游戏的例子来说,如果加入一个方法fly(),那么就算是橡皮鸭(RubberDuck)类也一定会具备fly()的行为。

2、这种方法并不能有效的解决代码重复问题。拿上一条中的fly()方法来说,既然不同的鸭子具有不同的飞行方式,则fly()方法的方法体一定是写在子类中;而不同种类的鸭子的飞行方式也可能是相同的,所以我们就可能不得不在多个鸭子中使用相同的fly()方法,而在另外一些鸭子中使用另一种fly()方法。

二、增加接口:

我们可以把Duck父类中的fly()方法提取出来定义成接口,称为Flyable,其中定义一个抽象方法fly(),让可以飞的Duck子类实现这个接口并实现fly()方法。

使用接口有效的解决了上面的第一个问题,即可以有效的控制各个子类的行为范围,不会出现“子类具有父类的所有方法”的情况了。但是,JAVA中的接口中不具备代码实现功能,所以这样做并没有解决代码重复的问题。

三、解决问题:

我们需要找出应用中可能需要变化的地方,把它们独立出来,不要和那些不需要变化的代码混在一起,即把会变化的部分取出并封装起来,一边以后可以轻易的改动或扩展此部分,而不影响不需要变化的部分。

在上面的两次尝试(使用继承、增加接口)中,我们都只是把共有的属性和行为抽出来封装成父类或接口,但在这里,我们要尽量两次封装,即在业务类上面还有两层封装类。对于一种行为,我们首先将这种行为抽取出来作为一个总的行为接口,然后再在这个接口下面定义多个不同的实现类,最后再在业务类中调用父类完成业务。简单的说,在上面两种尝试中,我们只是定义了两个互不相关的行为,而在这种方法中,我们定义的是一组有关联的行为。

拿我们这个例子中的fly()方法举例,飞,可能是用翅膀飞(FlyWithWings),也可能是坐火箭飞(FlyRocketPower)。因此,我们定义一个总的接口FlyBehavior,在这个接口中定义一个抽象方法fly()。再定义两个实现FlyBehavior接口的类FlyWithWings和FlyRocketPower,这两个类实现FlyBehavior接口,并实现接口中的fly()方法。另外,我们在Duck父类中定义一个FlyBehavior的接口变量,在生成鸭子实体的时候,给其FlyBehavior赋值,以此决定鸭子的飞行方式。我们还可以在Duck父类中定义一个设置飞行方式的方法setFlyBehavior(),来动态的改变鸭子的飞行方式。

以下贴出DEMO代码:

接口FlyBehavior中的代码:

1 public interface FlyBehavior {
2     void fly();
3 }

FlyBehavior接口的实现类FlyWithWings(用翅膀飞)类中的代码:

1 public class FlyWithWings implements FlyBehavior {
2     public void fly() {
3         System.out.println("我用翅膀飞!");
4     }
5 }

FlyBehavior接口的实现类FlyRocketPower(坐火箭飞)类中的代码:

1 public class FlyRocketPower implements FlyBehavior {
2     public void fly() {
3         System.out.println("我坐火箭飞!");
4     }
5 }

FlyBehavior接口的实现类FlyNoWay(不会飞)类中的代码:

1 public class FlyNoWay implements FlyBehavior {
2     public void fly() {
3         System.out.println("我不会飞!");
4     }
5 }

Duck父类中的代码:

 1 public abstract class Duck {
 2     private FlyBehavior flyBehavior; // 飞行行为接口对象
 3     // 设置鸭子的飞行行为方式
 4     public void setFlyBehavior(FlyBehavior flyBehavior) {
 5         this.flyBehavior = flyBehavior;
 6     }
 7     // 让鸭子飞行
 8     public void performFly() {
 9         this.flyBehavior.fly();
10     }
11     // 输出鸭子的样子
12     public abstract void display();
13 }

Duck的实体类RedHeadDuck(红头鸭)类中的代码:

 1 public class RedHeadDuck extends Duck {
 2     public RedHeadDuck() {
 3         this.display();
 4         super.setFlyBehavior(new FlyWithWings());
 5     }
 6 
 7     public void display() {
 8         System.out.println("我是红头鸭!");
 9     }
10 }

Duck的实体类RubberDuck(橡皮鸭)类中的代码:

 1 public class RubberDuck extends Duck {
 2     public RubberDuck() {
 3         this.display();
 4         super.setFlyBehavior(new FlyRocketPower());
 5     }
 6 
 7     public void display() {
 8         System.out.println("我是橡皮鸭!");
 9     }
10 }

主函数Main中的代码:

 1 public class Main {
 2     public static void main(String args[]) {
 3         // 第一只鸭子:红头鸭
 4         Duck duck1 = new RedHeadDuck();
 5         duck1.performFly();
 6         // 第二只鸭子:橡皮鸭(由坐火箭飞改变为不会飞)
 7         Duck duck2 = new RubberDuck();
 8         duck2.performFly();
 9         duck2.setFlyBehavior(new FlyNoWay());
10         duck2.performFly();
11     }
12 }

四、总结:

本例主要用了策略模式。所谓策略模式,即定义算法族(几组行为),每组行为封装一种行为的不同表现形式,让他们之间可以互相替换。这种模式让算法的变化独立于使用算法的客户。

设计模式 之 策略模式

标签:

原文地址:http://www.cnblogs.com/blog-wzy/p/5116793.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!