初学《大话设计模式》——策略模式

一、策略模式是什么

概念:策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。
策略模式是一种定义一系列算法的方法,从概念上看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合

二、场景

做一个商场收银软件,营业员根据客户所购买商品的单价和数量,向客户收费。(商场可能会有打折满减等活动,设计的软件应该易扩展、易维护)

三、程序界面

这里写图片描述

四、程序代码

程序共有7个类
这里写图片描述

CashSuper.java

package strategy;

public abstract class CashSuper {

    public abstract double acceptCash(double money);
}

CashNormal.java

package strategy;

/**
* @ClassName: CashNormal
* @Description: 正常收费子类
*/ 
public class CashNormal extends CashSuper {

    @Override
    public double acceptCash(double money) {
        return money;
    }

}

CashRebate.java

package strategy;

/**
* @ClassName: CashRebate
* @Description: 打折收费子类
*/ 
public class CashRebate extends CashSuper {

    /**
    * @Fields moneyRabate : 折率
    */ 
    private double moneyRabate=1;

    public CashRebate(double moneyRebate) {
        this.moneyRabate=moneyRebate;
    }
    @Override
    public double acceptCash(double money) {

        return money*moneyRabate;
    }

}

CashReturn.java

package strategy;

/**
* @ClassName: CashReturn
* @Description: 满减收费子类
*/ 
public class CashReturn extends CashSuper {
    /**
    * @Fields moneyCondition : 满
    */ 
    private double moneyCondition=0;

    /**
    * @Fields moneyReturn : 减
    */ 
    private double moneyReturn=0;

    public CashReturn(double moneyCondition,double moneyReturn) {
        this.moneyCondition=moneyCondition;
        this.moneyReturn=moneyReturn;
    }
    @Override
    public double acceptCash(double money) {
        double result=money;
        if(money>=moneyCondition){
            result=money-Math.floor(money/moneyCondition)*moneyReturn;
        }
        return result;
    }

}

CashContext.java

package strategy;

/**
* @ClassName: CashContext
* @Description: 策略类
*/ 
public class CashContext {

    private CashSuper cs;

    public CashContext(CashSuper cashSuper) {
        this.cs=cashSuper;
    }

    public double getResult(double money) {
        return cs.acceptCash(money);
    }
}

MyFrame.java

package strategy;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class MyFrame extends JFrame{

    public static JPanel lowPanel,topPanel,hidePanel,basepPanel;

    public static JLabel priceLabel,numLabel,typeLabel,startLabel,endLabel;

    // 输入框
    public static JTextField priceTextField,numTextField,starTextField,endTextField;

     //按钮
    public static JButton submitButton,resetButton;

    //文本框
    public static JTextArea  textArea;
    public static JScrollPane textScroll;

    //下拉框
    public static JComboBox<String> jcb;

    //监听器
    private MyListener listener=new MyListener();

    //总金额
    public static double totalMoney=0;

    public MyFrame() {
        //设置文本框字体
        Font textFont=new Font("宋体", Font.PLAIN, 20);
        //定义顶部组件
        topPanel=setTopPanel();

        //定义中间显示框
        textArea=new JTextArea(20,10);
        textScroll=new JScrollPane(textArea);
        textArea.setFont(textFont);
        textArea.setEditable(false);
        //定义底部组件
        lowPanel=new LowPanel();
        basepPanel=new JPanel();
        //定义各组件位置
        basepPanel.setLayout(null);
        topPanel.setBounds(10, 5, 400, 130);
        textScroll.setBounds(10, 140, 380, 120);
        lowPanel.setBounds(10, 270, 400, 120);
        basepPanel.add(topPanel);
        basepPanel.add(textScroll);
        basepPanel.add(lowPanel);

        this.setLayout(null);
        basepPanel.setBounds(0, 0, 420, 400);
        this.add(basepPanel);
        this.setTitle("商场收银系统") ;
        setSize(420, 400);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setLocation(350,350);
    }


    /**
    * @Title: setTopPanel
    * @Description: 定义顶部组件
    * @return   
    * @return JPanel    返回类型
    * @throws
    */ 
    private JPanel setTopPanel() {
        JPanel panel=new JPanel();
        //重置布局
        panel.setLayout(null);
        priceLabel=new JLabel("单价:");
        numLabel=new JLabel("数量:");
        typeLabel=new JLabel("计算方式:");
        startLabel=new JLabel("打");
        endLabel=new JLabel("折");

        priceTextField=new JTextField();
        numTextField=new JTextField();
        starTextField=new JTextField();
        endTextField=new JTextField();

        String[] typeStrings={"正常价格","打折","满减"};
        jcb=new JComboBox<>(typeStrings);
        jcb.addItemListener(listener);

        hidePanel=new JPanel();

        submitButton=new JButton("确定");
        resetButton=new JButton("重置");
        submitButton.addActionListener(listener);
        resetButton.addActionListener(listener);

        //设置各组件的位置
        priceLabel.setBounds(5, 5, 100, 30);
        priceTextField.setBounds(110, 5, 110, 30);
        submitButton.setBounds(270, 5, 100, 30);
        numLabel.setBounds(5, 45, 100, 30);
        numTextField.setBounds(110, 45, 110, 30);
        resetButton.setBounds(270, 45, 100, 30);
        typeLabel.setBounds(5, 85, 100, 30);
        jcb.setBounds(110, 85, 80, 30);
        hidePanel.setBounds(190, 85, 200, 30);

        panel.add(priceLabel);
        panel.add(priceTextField);
        panel.add(submitButton);
        panel.add(numLabel);
        panel.add(numTextField);
        panel.add(resetButton);
        panel.add(typeLabel);
        panel.add(jcb);
        panel.add(hidePanel);
        return panel;
    }


    //内部类,顶部组件
    class LowPanel extends JPanel{
        Font font=new Font("宋体", Font.PLAIN, 30);
        @Override
        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(Color.black);
            g.setFont(font);
            g.drawString("总计:"+String.format("%.2f", totalMoney)    +"元", 20, 50);
        }
    }


}

MyListener.java

package strategy;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JOptionPane;

public class MyListener implements ActionListener,ItemListener{

    static MyFrame myFrame;

    private CashContext cashContext=null;

    private double money;
    private int count;
    private String type;
    private String typeString;
    private double moneyCondition=0;
    private double moneyReturn=0;
    private double result=0;

    public static void main(String[] args) {
        myFrame=new MyFrame();
    }
    @Override
    public void actionPerformed(ActionEvent e) {

        //点击确定按钮
        if(e.getSource()==MyFrame.submitButton){
            try {
                money=Double.valueOf(MyFrame.priceTextField.getText());
                count=Integer.valueOf(MyFrame.numTextField.getText());

                type=(String) MyFrame.jcb.getSelectedItem();

                switch (type) {
                case "正常价格":
                    cashContext=new CashContext(new CashNormal()); 
                    typeString=type;
                    break;

                case "打折":
                    moneyCondition=Double.valueOf(MyFrame.starTextField.getText());
                    cashContext=new CashContext(new CashRebate(moneyCondition/10)); 
                    typeString="打"+moneyCondition+"折";
                    break;
                case "满减":
                    moneyCondition=Double.valueOf(MyFrame.starTextField.getText());
                    moneyReturn=Double.valueOf(MyFrame.endTextField.getText());
                    cashContext=new CashContext(new CashReturn(moneyCondition,moneyReturn));
                    typeString="满"+moneyCondition+"减"+moneyReturn;
                    break;
                default:
                    break;
                }
                //获取实际付款金额
                result=cashContext.getResult(money*count);
                MyFrame.totalMoney+=result;
                //显示框输出
                String str="单价:"+money+" 数量:"+count+" "+typeString+" 合计:"+result+"\n";
                MyFrame.textArea.append(str);
                MyFrame.lowPanel.repaint();
            } catch (NumberFormatException e1) {
                //输入非数字时抛出异常
                //弹出错误提示框
                JOptionPane.showMessageDialog(myFrame, "请勿输入非数字", 
                        "错误提示", JOptionPane.ERROR_MESSAGE);
            }
        }else if (e.getSource()==MyFrame.resetButton) {
            //点击重置按钮
            MyFrame.priceTextField.setText("");
            MyFrame.numTextField.setText("");
            MyFrame.starTextField.setText("");
            MyFrame.endTextField.setText("");
            MyFrame.textArea.setText("");
            MyFrame.totalMoney=0;
            MyFrame.topPanel.remove(MyFrame.hidePanel);
            MyFrame.jcb.setSelectedIndex(0);
            MyFrame.basepPanel.updateUI();
            MyFrame.basepPanel.repaint();
            MyFrame.lowPanel.repaint();
        }


    }


    @Override
    public void itemStateChanged(ItemEvent e) {
        //若下拉框的选择有变化
        if(e.getStateChange()==ItemEvent.SELECTED){
            if(MyFrame.jcb.getSelectedIndex()==1){
                //若是打折
                MyFrame.hidePanel.removeAll();
                MyFrame.startLabel.setText("打");
                MyFrame.endLabel.setText("折");
                MyFrame.startLabel.setBounds(30, 0, 20, 30);
                MyFrame.starTextField.setBounds(55, 0, 100, 30);
                MyFrame.endLabel.setBounds(160, 0, 35, 30);
                MyFrame.hidePanel.setLayout(null);
                MyFrame.hidePanel.add(MyFrame.startLabel);
                MyFrame.hidePanel.add(MyFrame.starTextField);
                MyFrame.hidePanel.add(MyFrame.endLabel);
                MyFrame.hidePanel.setBounds(190, 85, 200, 30);
                MyFrame.topPanel.add(MyFrame.hidePanel);
                MyFrame.basepPanel.updateUI();
                MyFrame.basepPanel.repaint();
            }else if (MyFrame.jcb.getSelectedIndex()==2) {
                //若是满减
                MyFrame.hidePanel.removeAll();
                MyFrame.startLabel.setText("满");
                MyFrame.endLabel.setText("减");
                MyFrame.startLabel.setBounds(2, 0, 18, 30);
                MyFrame.starTextField.setBounds(22, 0, 76, 30);
                MyFrame.endLabel.setBounds(100, 0, 20, 30);
                MyFrame.endTextField.setBounds(122, 0, 76, 30);
                MyFrame.hidePanel.setLayout(null);
                MyFrame.hidePanel.add(MyFrame.startLabel);
                MyFrame.hidePanel.add(MyFrame.starTextField);
                MyFrame.hidePanel.add(MyFrame.endLabel);
                MyFrame.hidePanel.add(MyFrame.endTextField);
                MyFrame.hidePanel.setBounds(190, 85, 200, 30);
                MyFrame.topPanel.add(MyFrame.hidePanel);
                MyFrame.basepPanel.updateUI();
                MyFrame.basepPanel.repaint();
            }else if (MyFrame.jcb.getSelectedIndex()==0) {
                MyFrame.topPanel.remove(MyFrame.hidePanel);
                MyFrame.basepPanel.updateUI();
                MyFrame.basepPanel.repaint();
            }
        }

    }

}

五、策略模式的优点

策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。对于打折、满减或其他的算法其实都是对实际商品的一种收费方式,通过继承可以得到它们的公共功能(公共功能就是计算费用的结果getResult()),这使得算法间有了抽象的父类CashSuper。另一个优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值