设计模式(1)---Strategy模式

Strategy模式(行为模式)

1.概述

在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。

2.问题

如何让算法和对象分开来,降低他们之间的耦合度,使得算法可以独立于使用它的客户而变化?

3.解决方案

策略模式:它定义了一系列算法,把每一个算法封装起来,让它们之间可以相互替换,本模式使得算法可独立于使用它的客户而变化。

4.结构

5.例子

商场收银软件:营业员根据顾客所购买商品的单价和数量,计算总价。商场可能会有促销活动,比如全场打8折,全场打5折,买200返100等。

实现方式一:可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的打折算法;当然也可以将这些打折算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的打折算法,需要修改封装算法类的源代码。该类代码将较复杂,维护较为困难。

实现方式二:使用策略模式。代码如下:

1 package strategy;
2 /*
3  * 策略类
4  */
5 public interface Strategy {
6      double Promote(double money);
7 }
 1 package strategy;
 2 /*
 3  * 不使用打折的具体策略类
 4  */
 5 public class CashNormalImpl implements Strategy {
 6
 7     public CashNormalImpl() {
 8
 9     }
10
11     @Override
12     public double Promote(double money) {
13
14         return money;
15     }
16
17 }
 1 package strategy;
 2 /*
 3  * 使用按比例打折的具体策略类
 4  */
 5 public class CashRebateImpl implements Strategy {
 6
 7     private double moneyRebate ;
 8     public CashRebateImpl(double moneyRebate) {
 9         this.moneyRebate = moneyRebate ;
10     }
11
12     @Override
13     public double Promote(double money) {
14
15         return money*moneyRebate;
16     }
17
18 }
 1 package strategy;
 2 /*
 3  * 使用返利打折方式的具体策略类
 4  */
 5 public class CashReturnImpl implements Strategy {
 6
 7     private double moneyCondition ;
 8     private double moneyReturn ;
 9
10     public CashReturnImpl(double moneyCondition , double moneyReturn) {
11         this.moneyCondition = moneyCondition ;
12         this.moneyReturn = moneyReturn ;
13     }
14
15     @Override
16     public double Promote(double money) {
17         double result = 0.0d;
18         if (money >= moneyCondition){
19             result = money - Math.floor(money/moneyCondition) * moneyReturn ;
20         }
21         return result;
22     }
23
24 }
 1 package strategy;
 2 /*
 3  * Context类
 4  */
 5 public class CashContext {
 6
 7     //Strategy对象的引用
 8     private Strategy contreteStrategy = null ;
 9
10     public CashContext(String str) {
11         if (str.equals("正常收费")){
12             contreteStrategy = new CashNormalImpl() ;
13         }else if (str.equals("打八折")){
14             contreteStrategy = new CashRebateImpl(0.8) ;
15         }else if (str.equals("打五折")){
16             contreteStrategy = new CashRebateImpl(0.5) ;
17         }else if (str.equals("满200返100")){
18             contreteStrategy = new CashReturnImpl(200, 100) ;
19         }
20
21     }
22
23     public double getResult(double money){
24         //当添加具体策略类时,这条代码也不用变,利用的多态的特点
25         return contreteStrategy.Promote(money);
26     }
27
28 }

界面(部分代码):

 1 btnOK.addActionListener(new ActionListener() {
 2               @Override
 3               public void actionPerformed(ActionEvent e) {
 4                 CashContext context = new CashContext(boxStrategy.getSelectedItem().toString()) ;
 5                 double price = Double.parseDouble(textPrice.getText()) ;
 6                 double num = Double.parseDouble(textNum.getText()) ;
 7                 double total = context.getResult(price*num);
 8                 sum += total ;
 9                 textSum.setText(String.valueOf(sum));
11                 textNum.setText("");
12                 textPrice.setText("");
13
14               }
15           });

界面(完整代码):

  1 package strategy;
  2
  3 import java.awt.Font;
  4 import java.awt.event.ActionEvent;
  5 import java.awt.event.ActionListener;
  6 import java.text.SimpleDateFormat;
  7 import java.util.Date;
  8
  9 import javax.swing.JButton;
 10 import javax.swing.JComboBox;
 11 import javax.swing.JFrame;
 12 import javax.swing.JLabel;
 13 import javax.swing.JOptionPane;
 14 import javax.swing.JPanel;
 15 import javax.swing.JScrollPane;
 16 import javax.swing.JTextArea;
 17 import javax.swing.JTextField;
 18
 19
 20
 21 public class CashFrame extends JFrame {
 22
 23     private JPanel contentPane = new JPanel() ;//主面板
 24
 25
 26
 27     private JLabel labPrice ; //单价提示文本
 28     private JTextField textPrice ; //单价设置框
 29     private JButton btnOK ; //确定
 30
 31     private JLabel labNum ; //数量设置提示文本
 32     private JTextField textNum ;  //数量设置框
 33     private JButton btnReset ; //重置
 34
 35     private JLabel labStrategy ; //策略设置提示文本
 36     private JComboBox  boxStrategy ;  //策略设置框
 37
 38     private JScrollPane scrollPane ; // 滚动面板
 39     private JTextArea textArea ; //信息显示
 40
 41     private JLabel labSum ; //总价提示文本
 42     private JLabel textSum ; //总价设置框
 43     private double sum = 0.0D ;//总价
 44
 45     private static CashFrame instance ;
 46
 47     private CashFrame(){
 48         init() ;
 49         UiUtil.setFrameCenter(this);
 50         this.setTitle("商场收银系统") ;
 51         this.setResizable(false);
 52         this.setVisible(true);
 53     }
 54
 55     public synchronized static CashFrame getInstance(){
 56         if (instance == null){
 57             instance = new CashFrame();
 58         }
 59         return instance ;
 60     }
 61
 62     public void init(){
 63          this.setBounds(200,100,450,450);
 64          this.setDefaultCloseOperation(EXIT_ON_CLOSE);
 65          this.setContentPane(contentPane);
 66
 67          contentPane.setLayout(null);
 68          /*----------------------------*/
 69          labPrice = new JLabel("单价: ") ;
 70          labPrice.setBounds(40,20,80,30);
 71          contentPane.add(labPrice) ;
 72
 73          textPrice = new JTextField() ;
 74          textPrice.setBounds(90,20,150,30);
 75          contentPane.add(textPrice) ;
 76
 77          btnOK = new JButton("确定") ;
 78          btnOK.setBounds(290,20,80,30);
 79          contentPane.add(btnOK) ;
 80
 81
 82          /*----------------------------*/
 83          labNum = new JLabel("数量: ") ;
 84          labNum.setBounds(40,60,80,30);
 85          contentPane.add(labNum) ;
 86
 87          textNum = new JTextField() ;
 88          textNum.setBounds(90,60,150,30);
 89          contentPane.add(textNum) ;
 90
 91          btnReset = new JButton("重置") ;
 92          btnReset.setBounds(290,60,80,30);
 93          contentPane.add(btnReset) ;
 94
 95          /*----------------------------*/
 96          labStrategy = new JLabel("促销方式: ") ;
 97          labStrategy.setBounds(15,100,80,30);
 98          contentPane.add(labStrategy) ;
 99
100          boxStrategy = new JComboBox() ;
101          boxStrategy.setBounds(90,100,150,30);
102          contentPane.add(boxStrategy) ;
103          boxStrategy.addItem("正常收费");
104          boxStrategy.addItem("打八折");
105          boxStrategy.addItem("打五折");
106          boxStrategy.addItem("满200返100");
107
108          /*----------------------------*/
109          textArea = new JTextArea() ;
110          textArea.setBounds(0,0,400,200);
111          textArea.setEditable(false);
112          textArea.setFont(new Font("宋体", Font.PLAIN, 15));
113
114          scrollPane = new JScrollPane(textArea) ;
115          scrollPane.setBounds(20,145,400,200);
116          scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
117          scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
118
119          contentPane.add(scrollPane) ;
120          /*----------------------------*/
121
122          labSum = new JLabel("总价: ") ;
123          labSum.setBounds(40,370,80,30);
124          contentPane.add(labSum) ;
125
126          textSum = new JLabel() ;
127          textSum.setBounds(90,370,150,30);
128          contentPane.add(textSum) ;
129
130          btnOK.addActionListener(new ActionListener() {
131               @Override
132               public void actionPerformed(ActionEvent e) {
133                 CashContext context = new CashContext(boxStrategy.getSelectedItem().toString()) ;
134                 double price = Double.parseDouble(textPrice.getText()) ;
135                 double num = Double.parseDouble(textNum.getText()) ;
136                 double total = context.getResult(price*num);
137                 sum += total ;
138                 showInfo("单价:"+textPrice.getText()+" 数量:"+textNum.getText()+" 方式:"+boxStrategy.getSelectedItem().toString()+"  合计:"+String.valueOf(total));
139                 textSum.setText(String.valueOf(sum));
140                 textNum.setText("");
141               textPrice.setText("");
142
143               }
144           });
145
146          btnReset.addActionListener(new ActionListener() {
147                @Override
148                public void actionPerformed(ActionEvent e) {
149                    textNum.setText("");
150                    textPrice.setText("");
151                    textSum.setText("");
152                    textArea.setText("");
153
154                }
155            });
156
157     }
158
159     public void showInfo(String info){
160         textArea.append(info+"\r\n");
161         textArea.setCaretPosition(textArea.getText().length()) ;//光标定位到最后一行  可以让滚动条保持在最下方
162     }
163
164     public static void main(String[] args) {
165         instance = new CashFrame() ;
166
167     }
168
169 }

6.适用性

当存在以下情况时使用Strategy模式
1)• 一个系统需要动态地在几种算法中选择一种。
2)• 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间 /时间权衡的算法。当这些变体实现为一个算法的类层次时 ,可以使用策略模式。
3)• 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
4)• 一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

7.优点

(1)所有这些打折算法完成的都是相同的工作,只是实现不同,策略模式可以以相同的方式调用所有的算法,降低了对象与算法的耦合。

(2)Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。

(3)简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

(4)消除了一些if else条件语句 :Strategy模式提供了用条件语句选择所需的行为以外的另一种选择。当不同的行为堆砌在一个类中时 ,很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的Strategy类中消除了这些条件语句。含有许多条件语句的代码通常意味着需要使用Strategy模式。

8.总结

1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
2)在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。2)
3)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

时间: 2024-08-10 19:19:20

设计模式(1)---Strategy模式的相关文章

C++设计模式---Strategy模式

一.前言 学习的第一个设计模式!不知道理解的对不对,期望大家一起多交流~ Strategy模式:策略模式,定义了算法族,分别封装起来,此模式可以让算法的变化独立于使用算法的客户.Strategy模式将逻辑算法封装到一个类中,通过组合的方式将具体的算法实现在组合对象中,再通过委托的方式将抽象的接口的实现委托给组合对象实现.其模型结构图如下: 二.Strategy策略实例 最近在写遥感影像融合相关算法,PCA.Brovey和SFIM算法,正好可以用于这次学习Strategy策略. 关于这三个融合算法

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

Strategy模式是一种行为型设计模式,它将算法一个个封装起来,在某一时刻能够互换地使用其中的一个算法.从概念上看,所有这些算法完成的都是相同的工作,只是实现不同而已. 动机 在开发中,我们常常会遇到概念上相同,处理方法不同的任务,例如,对一件商品使用不同的税额计算方法来计算其价格.一般来说,有以下的方法来处理: 复制和粘贴(一份代码具有两个版本,维护成本大) 使用switch或者if语句,用一个变量指定各种情况(分支会变得越来越长) 函数指针或者委托(无法维持对象的状态) 继承(需求变化时,

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

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

设计模式-strategy模式

策略模式 <设计模式>一书中对策略模式的意图是这样叙述的: 定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换,Strategy模式使算法可以独立于使用他的客户而变化. 仔细分析 在不同的环境下,每个类处理事情使用的算法是不一样的,所以针对不同环境,我们可以灵活使用这些算法.这样可以使得算法独立于客户,可以根据所处上下文,使用不同的业务规则或算法.

C++设计模式实现--策略(Strategy)模式

一. 举例说明 以前做了一个程序,程序的功能是评价几种加密算法时间,程序的使用操作不怎么变,变的是选用各种算法. 结构如下: Algorithm:抽象类,提供算法的公共接口. RSA_Algorithm:具体的RSA算法. DES_Algorithm:具体的DES算法. BASE64_Algorithm:具体的Base64算法. 在使用过程中,我只需要对外公布Algorithm_Context这个类及接口即可. 代码实现: [cpp] view plaincopy //策略类 class Alg

Strategy模式详解--设计模式(13)

Strategy模式来源:        在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件判断语句来进行选择.这两种实现方法我们都可以称之为硬编

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

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

设计模式:策略模式(Strategy)

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 策略模式的角色: 1. 抽象策略角色(Strategy):策略类,通常由一个接口或者抽象类实现 2. 具体策略角色(ConcreteStrategy):包装了相关的算法和行为 3. 环境角色(Context):持有一个策略类的引用,最终给客户端调用 这里引用参考资料3中的例子来详细说明一下策略模式. "赔了夫人又折兵"--这个是<三国演义>里的著名桥段,主要是说刘备要去

Strategy Pattern ava设计模式之策略模式

简介 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式.简单理解就是一组算法,可以互换,再简单点策略就是封装算法. 意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决 在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护. 何时使用 一个系统有许多许多类,而区分它们的只是他们直接的行为. 如何解决 将这些算法封装成一个一个的类,任意地替换. 主要角色 上下文Context,