zoukankan      html  css  js  c++  java
  • 设计模式(1)---策略模式

    策略模式 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+"
    ");
    161         textArea.setCaretPosition(textArea.getText().length()) ;//光标定位到最后一行  可以让滚动条保持在最下方
    162     }
    163 
    164     public static void main(String[] args) {
    165         instance = new CashFrame() ;
    166 
    167     }
    168 
    169 }
    View Code

    6.适用性

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

    7.优点

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

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

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

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

     

    8.总结

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

     

    9.策略模式在java容器布局管理中的应用

    Container 相当于环境类

    LayoutManager  相当于抽象策略类

    而具体策略类是LayoutManager的子类,也就是各种具体的布局类,它们封装了不同的布局方式。

     1 public class Container extends Component {
     2     LayoutManager layoutMgr;
     3 
     4     public void setLayout(LayoutManager mgr) {
     5     layoutMgr = mgr;
     6     if (valid) {
     7         invalidate();
     8     }
     9     }
    10 
    11 
    12 }
  • 相关阅读:
    [转] ORACLE 错误编号表一
    基于CkEditor实现.net在线开发之路(1)
    跨行清算系统的实现原理
    应用程序域
    支付机构客户备付金存管办法
    数据库培训二期试题
    MYSQL开发规范
    详解线上线下收单业务(一)第三方支付
    Solr安装配置说明
    进程(Process)
  • 原文地址:https://www.cnblogs.com/mengchunchen/p/5723818.html
Copyright © 2011-2022 走看看