設計模式(1)---策略模式

策略模式 Strategy(行爲型模式)java

 

1.概述算法

在軟件構建過程當中,某些對象使用的算法可能多種多樣,常常改變,若是將這些算法都編碼到對象中,將會使對象變得異常複雜;並且有時候支持不使用的算法也是一個性能負擔。設計模式

 

2.問題數據結構

如何讓算法和對象分開來,下降他們之間的耦合度,使得算法能夠獨立於使用它的客戶而變化?app

 

3.解決方案ide

策略模式:它定義了一系列算法,把每個算法封裝起來,讓它們之間能夠相互替換,本模式使得算法可獨立於使用它的客戶而變化。佈局

 

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 }
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 }
相關文章
相關標籤/搜索