《大话设计模式》java实现:第二章-策略模式

《大话设计模式》java实现:第二章-策略模式

第二章是使用策略模式实现商场收银系统,使收银系统的促销策略可以灵活更改。

1. 原始代码实现:

package gof;  /*  * 《大话设计模式》第二章策略模式  * 实现商场收银系统,可以选择不同促销策略  */  import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;  public class StrategyPattern {     public static void main(String[] args) {         new Gui();     } }  // 收银系统UI class Gui {     private JFrame frame;     private JTextField numberField;     private JTextField priceField;     private JComboBox<String> discountBox;     private JLabel resultLabel;      public Gui() {         frame = new JFrame("商场收银系统");         frame.setSize(400, 300);         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         frame.setLayout(new GridLayout(5, 2));          // 输入商品数量         JLabel numberLabel = new JLabel("商品数量:");         numberField = new JTextField();         frame.add(numberLabel);         frame.add(numberField);          // 输入商品单价         JLabel priceLabel = new JLabel("商品单价:");         priceField = new JTextField();         frame.add(priceLabel);         frame.add(priceField);          // 选择折扣方式         JLabel discountLabel = new JLabel("折扣方式:");         discountBox = new JComboBox<>(new String[]{"无折扣", "打八折", "满二十减五"});         frame.add(discountLabel);         frame.add(discountBox);          // 计算按钮         JButton calcButton = new JButton("计算");         calcButton.addActionListener(new ActionListener() {             @Override             public void actionPerformed(ActionEvent e) {                 calculate();             }         });         frame.add(calcButton);          // 显示结果         resultLabel = new JLabel("总计: 0.0");         frame.add(resultLabel);          frame.setVisible(true);     }      //计算函数     private void calculate() {         try {             double number = Double.parseDouble(numberField.getText());             double price = Double.parseDouble(priceField.getText());             String discount = (String) discountBox.getSelectedItem();              //调用计算类的计算函数             double result=SimpleCount.getCount(number, price, discount);             resultLabel.setText("总计: " + result);         } catch (NumberFormatException e) {             resultLabel.setText("输入错误!");         }     } }  // 商品价格结算类,最原始的实现。 class SimpleCount {     static double getCount(double number, double price, String discount) {         double sum = number * price;         // 打折         switch (discount) {             case "无折扣": {                 return sum;             }             case "打八折": {                 return sum * 0.8;             }             case "满二十减五": {                 return sum >=20 ? sum - 5 : sum;             }             default:                 throw new IllegalArgumentException("Unexpected value: " + discount);         }     } } 

在这个原始类中,每次更改促销策略都需要修改计算类和GUI,十分不方便。

简单工厂实现

为了节省篇幅,仅贴出需要修改的calculate()函数和其它类

private void calculate() {         try {             double number = Double.parseDouble(numberField.getText());             double price = Double.parseDouble(priceField.getText());             String discountString = (String) discountBox.getSelectedItem();                          //调用折扣工厂初始化折扣类,调用折扣类获取打折后的价格             double sum=number*price;             Discount discount=DiscountFactory.getDiscount(sum, discountString);             double result=discount.getDiscount();              resultLabel.setText("总计: " + result);         } catch (NumberFormatException e) {             resultLabel.setText("输入错误!");         }     } 
// 抽象打折类 abstract class Discount {     double sum;     abstract double getDiscount(); }  class NoDiscount extends Discount {     @Override     double getDiscount() {         return sum;     } }  class P8Discount extends Discount {     @Override     double getDiscount() {         return sum * 0.8;     } }  class Return5Discount extends Discount {     @Override     double getDiscount() {         return sum >= 20 ? sum - 5 : sum;     } }  // 打折类工厂 class DiscountFactory {     static Discount getDiscount(double sum, String discountString) {         Discount discount;          switch (discountString) {             case "无折扣": {                 discount = new NoDiscount();                 break;             }             case "打八折": {                 discount = new P8Discount();                 break;             }             case "满二十减五": {                 discount = new Return5Discount();                 break;             }             default:                 throw new IllegalArgumentException("Unexpected value: " + discountString);         }          // 在最后给成员变量赋值,避免写出多个赋值语句         discount.sum = sum;         return discount;     } } 

每次更改促销策略仍然需要修改计算类和GUI,十分不方便。

原始策略模式实现

删去了工厂,在计算函数中进行计算策略的实例化:

private void calculate() {         try {             double number = Double.parseDouble(numberField.getText());             double price = Double.parseDouble(priceField.getText());             String discountString = (String) discountBox.getSelectedItem();                          Discount discount;             //实例化discount             switch (discountString){             case "无折扣": {                 discount = new NoDiscount();                 break;             }             case "打八折": {                 discount = new P8Discount();                 break;             }             case "满二十减五": {                 discount = new Return5Discount();                 break;             } 			default: 				throw new IllegalArgumentException("Unexpected value: " + discountString); 			}             discount.sum=number*price;             //调用上下文获取折后价             DiscountContext discountContext=new DiscountContext(discount);             double result=discountContext.getDiscount();              resultLabel.setText("总计: " + result);         } catch (NumberFormatException e) {             resultLabel.setText("输入错误!");         }     } 

新增了一个策略上下文类:

// 抽象打折类 abstract class Discount {     double sum;     abstract double getDiscount(); }  class NoDiscount extends Discount {     @Override     double getDiscount() {         return sum;     } }  class P8Discount extends Discount {     @Override     double getDiscount() {         return sum * 0.8;     } }  class Return5Discount extends Discount {     @Override     double getDiscount() {         return sum >= 20 ? sum - 5 : sum;     } }  //使用原始策略模式 class DiscountContext{ 	private Discount discountClass; 	 	//构造时传入具体折扣策略类 	public DiscountContext(Discount discountSuper) { 		this.discountClass=discountSuper; 	} 	 	//调用策略类的方法得到值。 	public double getDiscount() { 		return discountClass.getDiscount(); 	} } 

这样一来,在客户端实例化算法类,如果需要修改算法类,就需要修改客户端的实例化代码。还是很不方便。

策略模式+简单工厂实现

将工厂模式和策略模式上下文结合,在策略模式上下文中实例化算法类。

修改calculate函数:

private void calculate() {     try {         double number = Double.parseDouble(numberField.getText());         double price = Double.parseDouble(priceField.getText());         String discountString = (String) discountBox.getSelectedItem();                  //调用上下文获取折后价         DiscountContext discountContext=new DiscountContext(number, price, discountString);         double result=discountContext.getDiscount();          resultLabel.setText("总计: " + result);     } catch (NumberFormatException e) {         resultLabel.setText("输入错误!");     } } 

在DiscountContxt类增加实例化语句:

//策略模式与简单工厂模式组合 class DiscountContext{ 	private Discount discount; 	 	//构造函数与简单工厂结合 	public DiscountContext(double number, double price, String discountString) { 		switch (discountString) {         case "无折扣": {             discount = new NoDiscount();             break;         }         case "打八折": {             discount = new P8Discount();             break;         }         case "满二十减五": {             discount = new Return5Discount();             break;         }         default:             throw new IllegalArgumentException("Unexpected value: " + discountString);     }  		// 在最后给成员变量赋值,避免写出多个赋值语句 		discount.sum = number*price; 	} 	 	//调用策略类的方法得到值。 	public double getDiscount() { 		return discount.getDiscount(); 	} } 

这种设计模式比上面几种更加清楚。GUI的计算函数调用上下文,算法的实例化和计算都由上下文来调用。这样GUI只依赖于上下文类。
与简单工厂的区别就在于简单工厂中,GUI的计算函数需要调用工厂类和算法类两个类,而策略模式+简单工厂只需要调用上下文类,进一步降低了耦合。

下面附上完全体代码:

package gof;  /*  * 《大话设计模式》第二章策略模式  * 实现商场收银系统,可以选择不同促销策略  */  import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;  public class StrategyPattern {     public static void main(String[] args) {         new Gui();     } }  // 收银系统UI class Gui {     private JFrame frame;     private JTextField numberField;     private JTextField priceField;     private JComboBox<String> discountBox;     private JLabel resultLabel;      public Gui() {         frame = new JFrame("商场收银系统");         frame.setSize(400, 300);         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         frame.setLayout(new GridLayout(5, 2));          // 输入商品数量         JLabel numberLabel = new JLabel("商品数量:");         numberField = new JTextField();         frame.add(numberLabel);         frame.add(numberField);          // 输入商品单价         JLabel priceLabel = new JLabel("商品单价:");         priceField = new JTextField();         frame.add(priceLabel);         frame.add(priceField);          // 选择折扣方式         JLabel discountLabel = new JLabel("折扣方式:");         discountBox = new JComboBox<>(new String[]{"无折扣", "打八折", "满二十减五"});         frame.add(discountLabel);         frame.add(discountBox);          // 计算按钮         JButton calcButton = new JButton("计算");         calcButton.addActionListener(new ActionListener() {             @Override             public void actionPerformed(ActionEvent e) {                 calculate();             }         });         frame.add(calcButton);          // 显示结果         resultLabel = new JLabel("总计: 0.0");         frame.add(resultLabel);          frame.setVisible(true);     }      private void calculate() {         try {             double number = Double.parseDouble(numberField.getText());             double price = Double.parseDouble(priceField.getText());             String discountString = (String) discountBox.getSelectedItem();                          //调用上下文获取折后价             DiscountContext discountContext=new DiscountContext(number, price, discountString);             double result=discountContext.getDiscount();              resultLabel.setText("总计: " + result);         } catch (NumberFormatException e) {             resultLabel.setText("输入错误!");         }     } }  // 抽象打折类 abstract class Discount {     double sum;     abstract double getDiscount(); }  class NoDiscount extends Discount {     @Override     double getDiscount() {         return sum;     } }  class P8Discount extends Discount {     @Override     double getDiscount() {         return sum * 0.8;     } }  class Return5Discount extends Discount {     @Override     double getDiscount() {         return sum >= 20 ? sum - 5 : sum;     } }  //策略模式与简单工厂模式组合 class DiscountContext{ 	private Discount discount; 	 	//构造函数与简单工厂结合 	public DiscountContext(double number, double price, String discountString) { 		switch (discountString) {         case "无折扣": {             discount = new NoDiscount();             break;         }         case "打八折": {             discount = new P8Discount();             break;         }         case "满二十减五": {             discount = new Return5Discount();             break;         }         default:             throw new IllegalArgumentException("Unexpected value: " + discountString);     }  		// 在最后给成员变量赋值,避免写出多个赋值语句 		discount.sum = number*price; 	} 	 	//调用策略类的方法得到值。 	public double getDiscount() { 		return discount.getDiscount(); 	} } 

发表评论

评论已关闭。

相关文章