每天一个设计模式(1):策略模式

1.策略模式

问题的提出

   一个模拟鸭子的游戏,游戏中出现各种鸭子,原本的设计是:设计了一个鸭子超类,并让各种鸭子继承此超类。

  但是要加新功能:比如会飞的鸭子?

  并且产品会不断更新。

  两种不好的解决方案:

  1.继承基类

  如果在基类中加上fly()方法,所有的鸭子都会继承,造成其他鸭子不想要的改变,比如玩具鸭子不想要会飞。

  原先设计中,鸭子叫的方法也有问题,各种鸭子叫声不一致,橡皮鸭不会叫。

  并且每当有新的鸭子子类出现,都需要检查并可能需要覆盖这些行为。

  2.继承接口

  如果使用接口来定义行为,子类根据需要实现接口,(比如,只有会飞的鸭子才实现Flyable接口),虽然可以做到行为的定制,但是却造成代码的无法复用,因为接口不提供实现代码。这就意味着,如果需要修改一个行为,那么必须在每一个定义此行为的类中修改它。

设计原则

  1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

  2.针对接口编程,而不是针对实现编程。

  “针对接口编程”真正的意思是“针对超类型(supertype)编程”,这里所谓的“接口”,更明确地说,变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,针对接口编程的关键就在多态

  利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。

  只要是具体实现此超类型的类所产生的对象,都可以指定给这个超类型的变量。这也意味着,声明类时不用理会以后执行时的真正对象类型。

  3.多用组合,少用继承。

  “有一个”可能比“是一个”更好。

  使用组合建立系统具有很大的弹性,不仅可以将算法族封装成类,更可以“在运行时动态地改变行为”,只要组合的行为对象符合正确的接口标准即可。

关于鸭子问题的解决方案

  分类变化的部分:将飞行和叫的动作从基类Duck中分离出来。

  利用接口代替每个行为:定义FlyBehavior与QuackBehavior行为接口,鸭子类并不实现这些接口,是由我们创造一组其他类专门实现FlyBehavior与QuackBehavior。

  这样的设计,可以让各种飞行的动作被其他的对象复用,并且新增行为也不会影响到既有行为。

  具体做法:在基类Duck中加入两个实例变量,分别为FlyBehavior flyBehavior与QuackBehavior quackBehavior,注意声明为接口类型,而不是具体的实现类型,每个鸭子对象都会动态地设置这些变量以在运行时引用正确的行为类型。

  然后在基类中实现方法,调用相应的变量的方法,比如:

  public void performFly()

  {

    flyBehavior.fly()

  }

  设定变量可以在子类的构造函数中进行,这样就可以为每个子类设定不同的行为,即变量指向不同的类(该类实现了相应的接口)的对象。

策略模式

  定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数,关系图如下:

图中ICalculator提供同意的方法,
AbstractCalculator是辅助类,提供辅助方法,接下来,依次实现下每个类:

首先统一接口:

public interface ICalculator {
    public int calculate(String exp);
}

辅助类:

 1 public abstract class AbstractCalculator {
 2
 3     public int[] split(String exp,String opt){
 4         String array[] = exp.split(opt);
 5         int arrayInt[] = new int[2];
 6         arrayInt[0] = Integer.parseInt(array[0]);
 7         arrayInt[1] = Integer.parseInt(array[1]);
 8         return arrayInt;
 9     }
10 }  

三个实现类:

 1 public class Plus extends AbstractCalculator implements ICalculator {
 2
 3     @Override
 4     public int calculate(String exp) {
 5         int arrayInt[] = split(exp,"\\+");
 6         return arrayInt[0]+arrayInt[1];
 7     }
 8 }
 9
10 public class Minus extends AbstractCalculator implements ICalculator {
11
12     @Override
13     public int calculate(String exp) {
14         int arrayInt[] = split(exp,"-");
15         return arrayInt[0]-arrayInt[1];
16     }
17
18 }
19
20 public class Multiply extends AbstractCalculator implements ICalculator {
21
22     @Override
23     public int calculate(String exp) {
24         int arrayInt[] = split(exp,"\\*");
25         return arrayInt[0]*arrayInt[1];
26     }
27 } 

简单的测试类:

1 public class StrategyTest {
2
3     public static void main(String[] args) {
4         String exp = "2+8";
5         ICalculator cal = new Plus();
6         int result = cal.calculate(exp);
7         System.out.println(result);
8     }
9 }  

输出:10

策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。

参考:

《Head Frist 设计模式》

http://www.cnblogs.com/mengdd/archive/2012/12/26/2834884.html

http://blog.csdn.net/zhangerqing/article/details/8243942

时间: 2024-11-05 20:31:09

每天一个设计模式(1):策略模式的相关文章

五分钟一个设计模式之策略模式

五分钟一个设计模式,用最简单的方法来描述设计模式. 开发一个小游戏 还是先来看个例子吧. 有一天老板一拍脑袋,想做一个游戏,于是把你找来,告诉你他的想法: 做一个最简单的闯关游戏,每个关卡都有一些小怪兽,而游戏的角色通过打死所有小怪兽来通关 角色可以使用武器,先做三四个简单的武器,有一般的武器,有厉害的武器,每个武器的伤害值不一样 游戏过程中,角色可以更换武器 先做一个角色,以后可能增加新角色,但不同角色之间的区别现在还没想好. 你作为这个新游戏的主程序员,要做的就是使程序的架构足够灵活,能够为

设计模式之策略模式(Strategy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

Head First 设计模式之一 策略模式

策略模式 定义 策略模式定义了算法族,分别封装起来,让他们之间可以相互转换,此模式让算法的变化独立于使用算法的客户. 实例 上面的定义看起来说的不太清楚,记定义无意义,理解策略模式还是要看书中的鸭子例子.假设设计一个模拟鸭子的游戏,鸭子的种类有很多,有红头鸭.绿头鸭等等,鸭子可以划水,可以呱嘎叫.在这个模拟游戏的实现上,自然会想到用继承的方法,定义一个鸭子基类,具体的鸭子类型继承自鸭子基类.如下图所示 所有鸭子都会飞.呱呱叫和游泳,这些功能由基类来实现,display函数用来输出鸭子实例的类型,

JavaScript设计模式之策略模式(学习笔记)

在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选择学习策略模式. 策略模式:定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户. 通常我并不会记得“牛顿第一定律”的具体内容,所以我也难保证我会对这个定义记得多久……用FE经常见到的东西来举个例子说明一下: $("div").animation(

大话设计模式_策略模式(Java代码)

策略模式:定义算法家族,分别封装,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户 简单描述:一个父类,多个子类实现具体方法.一个Context类持有父类的引用(使用子类实例化此引用),客户端代码只需要与此Context类交互即可 大话设计模式中的截图: 例子代码: 策略类: 1 package com.longsheng.strategy; 2 3 public abstract class Strategy { 4 5 public abstract double getR

设计模式之策略模式20170720

行为型设计模式之策略模式: 一.含义 策略模式是一种比较简单的模式,也叫做政策模式,其定义如下: 定义一组算法(可抽象出接口),将每个算法都封装起来,并且使它们之间可以互换(定义一个类实现封装与算法切换) 二.代码说明 1.主要有两个角色 1)Context封装角色 它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略,算法的直接访问,封装可能存在的变化. 2)策略角色 该类含有具体的算法 2.在用C实现过程中也是参考这种思想,以压缩,解压算法举例,具体实现如下: 1)策略模式使用场景

<二>读<<大话设计模式>>之策略模式

又和大家见面了,能够坚持写出第二篇文章真不错,好好加油. <<大话设计模式>>讲解策略模式是以商场收银软件程序开头的,那么问题来了,哪家商场收银软件强,开玩笑了.读过上篇文章<<简单工厂模式>>的知道,它有两个缺点:1.客户端依赖两个类,耦合性高:2.如果算法过多则需要写很多类.解决上面问题的就是策略模式了. 策略模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 商场收银软件:单价*打折算法=售价.

设计模式之策略模式C++实现

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 策略模式UML图如下: 举例: 游泳池中有不同种类的鸭子,有绿头鸭,红头鸭,橡皮鸭,木头鸭等.不同鸭子的特征或行为不同.绿头鸭(MallardDuck)可以叫声是"quack",会飞:橡皮鸭叫声是"queak",不会飞:木头鸭不会叫,也不会飞.利用面向对象原理来设计来泳池中的各种鸭.要求:1.可扩展性好,当有新鸭加入时或鸭的行为有变动时,不用大量改动代码:2.复用性

如何让孩子爱上设计模式 ——14.策略模式(Strategy Pattern)

如何让孩子爱上设计模式 --14.策略模式(Strategy Pattern) 描述性文字 本节讲解的是行为型设计模式中的第一个模式: 策略模式, 这个模式非常简单,也很好理解. 定义一系列的算法,把每个算法封装起来,并使得他们可以相互替换, 让算法独立于使用它的客户而变化. 一般用来替换if-else,个人感觉是面向过程与面向对象思想的 过渡,这里举个简易计算器的栗子,帮助理解~ 普通的if-else/switch计算器 普通的面向过程if-else简易计算器代码如下: 运行结果如下: 这里我

[design-patterns]设计模式之一策略模式

设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不是那么容易做到了.现实世界的问题复杂多样,如何将显示问题映射到我们编写的程序中本就是困难重重.另一方面,软件开发中一个不变的真理就是"一切都在变化之中",这种变化可能来自于程序本身的复杂度,也可能来自于客户不断变化的需求,这就要求我们在编写程序中一定要考虑变化的因素,将变化的因素抽离出来,