策略模式(策略设计模式)详解

在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法。

在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。

如果使用多重条件转移语句实现(即硬编码),不但使条件语句变得很复杂,而且增加、删除或更换算法要修改原代码,不易维护,违背开闭原则。如果采用策略模式就能很好解决该问题。

策略模式的定义与特点

策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

策略模式的主要优点如下。

  1. 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
  2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
  3. 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
  4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
  5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

其主要缺点如下。

  1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
  2. 策略模式造成很多的策略类。

策略模式的结构与实现

策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。

1. 模式的结构

策略模式的主要角色如下。

  1. 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  2. 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  3. 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

其结构图如图 1 所示。


图1 策略模式的结构图

2. 模式的实现

策略模式的实现代码如下:

package strategy;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CrabCookingStrategy implements ItemListener
{private JFrame f;private JRadioButton qz,hs;private JPanel CenterJP,SouthJP;private Kitchen cf;    //厨房private CrabCooking qzx,hsx;    //大闸蟹加工者   CrabCookingStrategy(){f=new JFrame("策略模式在大闸蟹做菜中的应用");f.setBounds(100,100,500,400);f.setVisible(true);       f.setResizable(false);f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);SouthJP=new JPanel();CenterJP=new JPanel();f.add("South",SouthJP);f.add("Center",CenterJP);qz=new JRadioButton("清蒸大闸蟹");hs=new JRadioButton("红烧大闸蟹");qz.addItemListener(this);hs.addItemListener(this);ButtonGroup group=new ButtonGroup();group.add(qz);group.add(hs);SouthJP.add(qz);SouthJP.add(hs);//---------------------------------cf=new Kitchen();    //厨房qzx=new SteamedCrabs();    //清蒸大闸蟹类hsx=new BraisedCrabs();    //红烧大闸蟹类}public void itemStateChanged(ItemEvent e){JRadioButton jc=(JRadioButton) e.getSource();if(jc==qz){cf.setStrategy(qzx);cf.CookingMethod(); //清蒸}else if(jc==hs){cf.setStrategy(hsx);cf.CookingMethod(); //红烧}CenterJP.removeAll();CenterJP.repaint();CenterJP.add((Component)cf.getStrategy());       f.setVisible(true);}public static void main(String[] args){       new CrabCookingStrategy();}
}
//抽象策略类:大闸蟹加工类
interface CrabCooking
{public void CookingMethod();    //做菜方法
}
//具体策略类:清蒸大闸蟹
class SteamedCrabs extends JLabel implements CrabCooking
{private static final long serialVersionUID=1L;public void CookingMethod(){this.setIcon(new ImageIcon("src/strategy/SteamedCrabs.jpg"));this.setHorizontalAlignment(CENTER);}
}
//具体策略类:红烧大闸蟹
class BraisedCrabs extends JLabel implements CrabCooking
{private static final long serialVersionUID=1L;public void CookingMethod(){this.setIcon(new ImageIcon("src/strategy/BraisedCrabs.jpg"));this.setHorizontalAlignment(CENTER);}
}
//环境类:厨房
class Kitchen
{private CrabCooking strategy;    //抽象策略public void setStrategy(CrabCooking strategy){this.strategy=strategy;}public CrabCooking getStrategy(){return strategy;}public void CookingMethod(){strategy.CookingMethod();    //做菜   }
}

程序运行结果如下:

具体策略A的策略方法被访问!
-----------------
具体策略B的策略方法被访问!

策略模式的应用实例

【例1】策略模式在“大闸蟹”做菜中的应用。

分析:关于大闸蟹的做法有很多种,我们以清蒸大闸蟹和红烧大闸蟹两种方法为例,介绍策略模式的应用。

首先,定义一个大闸蟹加工的抽象策略类(CrabCooking),里面包含了一个做菜的抽象方法 CookingMethod();然后,定义清蒸大闸蟹(SteamedCrabs)和红烧大闸蟹(BraisedCrabs)的具体策略类,它们实现了抽象策略类中的抽象方法;由于本程序要显示做好的结果图(点此下载要显示的结果图),所以将具体策略类定义成 JLabel 的子类;最后,定义一个厨房(Kitchen)环境类,它具有设置和选择做菜策略的方法;客户类通过厨房类获取做菜策略,并把做菜结果图在窗体中显示出来,图 2 所示是其结构图。


图2 大闸蟹做菜策略的结构图

程序代码如下:

package strategy;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CrabCookingStrategy implements ItemListener
{private JFrame f;private JRadioButton qz,hs;private JPanel CenterJP,SouthJP;private Kitchen cf;    //厨房private CrabCooking qzx,hsx;    //大闸蟹加工者   CrabCookingStrategy(){f=new JFrame("策略模式在大闸蟹做菜中的应用");f.setBounds(100,100,500,400);f.setVisible(true);       f.setResizable(false);f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);SouthJP=new JPanel();CenterJP=new JPanel();f.add("South",SouthJP);f.add("Center",CenterJP);qz=new JRadioButton("清蒸大闸蟹");hs=new JRadioButton("红烧大闸蟹");qz.addItemListener(this);hs.addItemListener(this);ButtonGroup group=new ButtonGroup();group.add(qz);group.add(hs);SouthJP.add(qz);SouthJP.add(hs);//---------------------------------cf=new Kitchen();    //厨房qzx=new SteamedCrabs();    //清蒸大闸蟹类hsx=new BraisedCrabs();    //红烧大闸蟹类}public void itemStateChanged(ItemEvent e){JRadioButton jc=(JRadioButton) e.getSource();if(jc==qz){cf.setStrategy(qzx);cf.CookingMethod(); //清蒸}else if(jc==hs){cf.setStrategy(hsx);cf.CookingMethod(); //红烧}CenterJP.removeAll();CenterJP.repaint();CenterJP.add((Component)cf.getStrategy());       f.setVisible(true);}public static void main(String[] args){       new CrabCookingStrategy();}
}
//抽象策略类:大闸蟹加工类
interface CrabCooking
{public void CookingMethod();    //做菜方法
}
//具体策略类:清蒸大闸蟹
class SteamedCrabs extends JLabel implements CrabCooking
{private static final long serialVersionUID=1L;public void CookingMethod(){this.setIcon(new ImageIcon("src/strategy/SteamedCrabs.jpg"));this.setHorizontalAlignment(CENTER);}
}
//具体策略类:红烧大闸蟹
class BraisedCrabs extends JLabel implements CrabCooking
{private static final long serialVersionUID=1L;public void CookingMethod(){this.setIcon(new ImageIcon("src/strategy/BraisedCrabs.jpg"));this.setHorizontalAlignment(CENTER);}
}
//环境类:厨房
class Kitchen
{private CrabCooking strategy;    //抽象策略public void setStrategy(CrabCooking strategy){this.strategy=strategy;}public CrabCooking getStrategy(){return strategy;}public void CookingMethod(){strategy.CookingMethod();    //做菜   }
}

程序运行结果如图 3 所示。


图3 大闸蟹做菜结果

【例2】用策略模式实现从韶关去婺源旅游的出行方式。

分析:从韶关去婺源旅游有以下几种出行方式:坐火车、坐汽车和自驾车,所以该实例用策略模式比较适合,图 4 所示是其结构图。


图4 婺源旅游结构图

策略模式的应用场景

策略模式在很多地方用到,如 Java SE 中的容器布局管理就是一个典型的实例,Java SE 中的每个容器都存在多种布局供用户选择。在程序设计中,通常在以下几种情况中使用策略模式较多。

  1. 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
  2. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
  3. 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
  4. 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
  5. 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。

策略模式的扩展

在一个使用策略模式的系统中,当存在的策略很多时,客户端管理所有策略算法将变得很复杂,如果在环境类中使用策略工厂模式来管理这些策略类将大大减少客户端的工作复杂度,其结构图如图 5 所示。


图5 策略工厂模式的结构图


转载地址:http://c.biancheng.net/view/1378.html

策略模式(策略设计模式)详解相关推荐

  1. 原型模式(设计模式详解)

    原型模式 描述 实现 使用场景 描述 原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需从头开始编写代码. 在原型模式中,一个原型对象作为模 ...

  2. 《设计模式详解》行为型模式 - 解释器模式

    解释器模式 6.11 解释器模式 6.11.1 概述 6.11.2 结构 6.11.3 案例实现 6.11.4 优缺点 6.11.5 使用场景 完整的笔记目录:<设计模式详解>笔记目录,欢 ...

  3. 《设计模式详解》行为型模式 - 备忘录模式

    备忘录模式 6.10 备忘录模式 6.10.1 概述 6.10.2 结构 6.10.3 案例实现 "白箱" 备忘录模式 "黑箱" 备忘录模式 6.10.4 优缺 ...

  4. 《设计模式详解》行为型模式 - 观察者模式

    观察者模式 6.6 观察者模式 6.6.1 概述 6.6.2 结构 6.6.3 案例实现 6.6.4 优缺点 6.6.5 使用场景 6.6.6 JDK 提供的实现 - Observable 示例 完整 ...

  5. 《设计模式详解》行为型模式 - 状态模式

    状态模式 6.5 状态模式 6.5.1 反例 6.5.2 结构 6.5.3 案例实现 6.5.4 优缺点 6.5.5 使用场景 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! 行为型 ...

  6. 《设计模式详解》行为型模式 - 职责链模式

    职责链模式 6.4 职责链模式 6.4.1 概述 6.4.2 结构 6.4.3 案例实现 6.4.4 优缺点 6.4.5 JavaWeb 源码 - FilterChain 完整的笔记目录:<设计 ...

  7. 《设计模式详解》行为型模式 - 命令模式

    命令模式 6.3 命令模式 6.3.1 概述 6.3.2 结构 6.3.3 案例实现 6.3.4 优缺点 6.3.5 使用场景 6.3.6 JDK 源码 - Runnable 完整的笔记目录:< ...

  8. 《设计模式详解》行为型模式 - 模板方法模式

    模板方法模式 6.1 模板方法模式 6.1.1 概述 6.1.2 结构 6.1.3 案例实现 6.1.3 优缺点 6.1.4 适用场景 6.1.5 JDK源码 - InputStream 完整的笔记目 ...

  9. 《设计模式详解》行为型模式 - 中介者模式

    中介者模式 6.7 中介者模式 6.7.1 概述 6.7.2 结构 6.7.3 案例实现 6.7.4 优缺点 6.7.5 使用场景 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! 6 ...

  10. 《设计模式详解》结构型模式 - 组合模式

    组合模式 5.6 组合模式 5.6.1 概述 5.6.2 结构 5.6.3 案例实现 5.6.4 组合模式的分类 5.6.5 优点 5.6.6 使用场景 完整的笔记目录:<设计模式详解>笔 ...

最新文章

  1. 计算机什么时候学汇编,[计算机基础] 汇编学习(1)
  2. 知识科普:布线系统的施工顺序是什么
  3. Attachment assignment block里选择的文件是如何传到application server
  4. facebook人脸照片_为什么您的Facebook照片看起来如此糟糕(以及您可以如何做)...
  5. html字符串生成器源代码
  6. 感知机算法python实现
  7. 201632位matlab下载_【科研利器】带你get“研”途上的MATLAB入门篇
  8. 多路查找树之2-3树的删除原理 - 数据结构和算法81
  9. 计算机cpu图片,电脑处理器天梯图2019
  10. 颜晖c语言设计答案,c语言程序设计 (何钦铭 颜晖 著)课后习题答案
  11. iOS App 性能优化总结
  12. Python制作表白爱心合集
  13. 操作系统—PV操作解决和尚打水问题
  14. IP地址、路由器、数据分片、地址管理、子网掩码、路由选择、公网与私网
  15. vue实现ZKT(中控)身份证读卡器读卡功能
  16. 世界首个由队伍拥有并运营的CS:GO电竞联盟FLASHPOINT成立
  17. 用 IAR C/C++ For ARM 编写嵌入式应用的启动细节
  18. 程序员是青春饭?该何去何从?
  19. proteus仿真arduino中调用DHT11/22温湿度传感器
  20. 计算机盘有百度云盘怎么删除文件,百度网盘的群内分享文件可以删除吗

热门文章

  1. 网易云音乐歌单制作词云图
  2. STM32H7内部Flash的读保护说明(Level0默认,Level1连接保护,Level2设备和自举保护)
  3. 手机浏览器,怎么访问电脑版的网页?
  4. 申论高效解题的步骤——按部就班
  5. aac格式怎么转换为MP3格式
  6. 【题解】10-19秀秀的森林(forest)
  7. 【好用的办公软件】万彩办公大师教程丨标准安装版/绿色免安装版/离线版区别
  8. cocoscreator的游戏背景适配方案
  9. Android 基础篇之环境配置
  10. android原生app转成web,转战WebApp: 最适合Android开发者的WebApp框架