策略模式(java)
2016-03-31 18:04
393 查看
一、概念
策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm
vary independently from clients that use it.)
![](http://images.cnblogs.com/cnblogs_com/colinsong/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F.gif)
图1 策略模式类图
优点:
1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)
参考阅读:
1. 2.
二、我的理解
其实这个策略模式和简单工厂模式一样,仅仅是对面向对象继承中常用的Override技术的一种应用。简单工厂模式中有一个工厂类,负责根据输入参数的不同来生成不同的子类,并将生成的子类作为基类返回(这样可以让客户端在使用的时候很方便)。客户端只需要调用工厂类创建一个基类的实例,然后调用这个实例的函数来实现自己的功能。而策略模式中的Context类的功能基本上就是对工厂类的强化版本,它也负责根据输入参数来生成不同的类,只是它并不返回生成类,而是将生成类所实现的功能接口包装一次,提供给客户。这样对客户来说,他们只需要知道这一个Context类就可以完成他们想要的功能,而不必再知道其他的信息。
三、策略模式与简单工厂模式结合的代码实现
下面以一个简单的商场收银系统为例,演示一下策略模式与简单工厂模式结合的使用。我将这个系统用两个工程实现。一个工程实现商场计费的业务功能,另一个工程用于实现POS机上的界面,也就是客户端。
首先介绍第一个工程:
1. 实现计费功能的基类(这里用抽象类实现):
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public abstract class BillingAlgorithm
4 {
5 public abstract double getBillingResult(double price, int quantity);
6 }
7 }
2. 实现具体计费功能的子类:
2.1 实现打折计费的子类:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public class BillingStrategy_Rebate:BillingAlgorithm
4 {
5 double discounts;
6 public BillingStrategy_Rebate(double discounts)
7 {
8 if (discounts < 0.0000001 || discounts >= 1)
9 {
10 this.discounts = 1;
11 }
12 else
13 {
14 this.discounts = discounts;
15 }
16 }
17
18 public override double getBillingResult(double price, int quantity)
19 {
20 return price * quantity * discounts;
21 }
22 }
23 }
2.2 实现返现计费功能的子类:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public class BillingStrategy_CashReturn:BillingAlgorithm
4 {
5 int CashCondition;
6 int CashReturn;
7 public BillingStrategy_CashReturn(int CashCondition, int CashReturn)
8 {
9 if (CashCondition <= 0)
10 {
11 CashCondition = 1;
12 }
13 if (CashReturn <= 0)
14 {
15 CashReturn = 1;
16 }
17 this.CashCondition = CashCondition;
18 this.CashReturn = CashReturn;
19 }
20
21 public override double getBillingResult(double price, int quantity)
22 {
23 double orignal = price * quantity;
24 int n = (int) (orignal / CashCondition);
25 return orignal - CashReturn * n;
26 }
27 }
28 }
29
3. Context类
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace ColinSong.DesignPattern.Strategy
2
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public class Billing
4
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//维护一个算法基类的实例
6
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
BillingAlgorithm billingAlgorithm;
7
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//简单工厂模式的构造函数
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Billing(string BillingStrategy)
10
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
switch (BillingStrategy)
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "打8折":
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_Rebate(0.8);
15
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "满200返40":
17
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_CashReturn(200, 40);
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
19
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
default:
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_Rebate(1);
21
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
22
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
23
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
24
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//策略模式的构造函数
25
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Billing(BillingAlgorithm billingAlgorithm)
26
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.billingAlgorithm = billingAlgorithm;
28
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
29
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//这是策略模式的典型特征
30
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public double GetResult(double price, int quantity)
31
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return billingAlgorithm.getBillingResult(price, quantity);
33
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
34
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
35
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
36
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
好,算法完成了,下面介绍客户端,界面如图2所示:
![](http://images.cnblogs.com/cnblogs_com/colinsong/%E5%95%86%E5%9C%BA%E6%94%B6%E9%93%B6%E7%B3%BB%E7%BB%9F%E7%95%8C%E9%9D%A2_%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F%E5%BA%94%E7%94%A8.JPG)
图2. 商场收银系统界面
下面看一下,确定按钮后面的代码:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
private void btnOK_Click(object sender, EventArgs e)
{
\\只需要知道这个Context类,实例化它;
Billing billing = new Billing(cbxBillingType.Text);
\\并调用它提供的方法,即可完成我们需要的功能。
double charge = billing.GetResult(double.Parse(txtPrice.Text),
int.Parse(txtQuantity.Text));
totalCash = totalCash + charge;
string itemShow = "单价:"+txtPrice.Text
+ "\t数量:"+txtQuantity.Text +
".\t实收:"+ charge.ToString()
+ "\t"+cbxBillingType.Text;
list.Items.Add(itemShow);
lblSum.Text = totalCash.ToString();
}
策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm
vary independently from clients that use it.)
![](http://images.cnblogs.com/cnblogs_com/colinsong/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F.gif)
图1 策略模式类图
优点:
1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)
参考阅读:
1. 2.
二、我的理解
其实这个策略模式和简单工厂模式一样,仅仅是对面向对象继承中常用的Override技术的一种应用。简单工厂模式中有一个工厂类,负责根据输入参数的不同来生成不同的子类,并将生成的子类作为基类返回(这样可以让客户端在使用的时候很方便)。客户端只需要调用工厂类创建一个基类的实例,然后调用这个实例的函数来实现自己的功能。而策略模式中的Context类的功能基本上就是对工厂类的强化版本,它也负责根据输入参数来生成不同的类,只是它并不返回生成类,而是将生成类所实现的功能接口包装一次,提供给客户。这样对客户来说,他们只需要知道这一个Context类就可以完成他们想要的功能,而不必再知道其他的信息。
三、策略模式与简单工厂模式结合的代码实现
下面以一个简单的商场收银系统为例,演示一下策略模式与简单工厂模式结合的使用。我将这个系统用两个工程实现。一个工程实现商场计费的业务功能,另一个工程用于实现POS机上的界面,也就是客户端。
首先介绍第一个工程:
1. 实现计费功能的基类(这里用抽象类实现):
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public abstract class BillingAlgorithm
4 {
5 public abstract double getBillingResult(double price, int quantity);
6 }
7 }
2. 实现具体计费功能的子类:
2.1 实现打折计费的子类:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public class BillingStrategy_Rebate:BillingAlgorithm
4 {
5 double discounts;
6 public BillingStrategy_Rebate(double discounts)
7 {
8 if (discounts < 0.0000001 || discounts >= 1)
9 {
10 this.discounts = 1;
11 }
12 else
13 {
14 this.discounts = discounts;
15 }
16 }
17
18 public override double getBillingResult(double price, int quantity)
19 {
20 return price * quantity * discounts;
21 }
22 }
23 }
2.2 实现返现计费功能的子类:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ColinSong.DesignPattern.Strategy
2 {
3 public class BillingStrategy_CashReturn:BillingAlgorithm
4 {
5 int CashCondition;
6 int CashReturn;
7 public BillingStrategy_CashReturn(int CashCondition, int CashReturn)
8 {
9 if (CashCondition <= 0)
10 {
11 CashCondition = 1;
12 }
13 if (CashReturn <= 0)
14 {
15 CashReturn = 1;
16 }
17 this.CashCondition = CashCondition;
18 this.CashReturn = CashReturn;
19 }
20
21 public override double getBillingResult(double price, int quantity)
22 {
23 double orignal = price * quantity;
24 int n = (int) (orignal / CashCondition);
25 return orignal - CashReturn * n;
26 }
27 }
28 }
29
3. Context类
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace ColinSong.DesignPattern.Strategy
2
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public class Billing
4
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//维护一个算法基类的实例
6
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
BillingAlgorithm billingAlgorithm;
7
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//简单工厂模式的构造函数
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Billing(string BillingStrategy)
10
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
switch (BillingStrategy)
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "打8折":
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_Rebate(0.8);
15
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "满200返40":
17
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_CashReturn(200, 40);
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
19
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
default:
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
billingAlgorithm = new BillingStrategy_Rebate(1);
21
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
break;
22
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
23
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
24
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//策略模式的构造函数
25
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Billing(BillingAlgorithm billingAlgorithm)
26
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.billingAlgorithm = billingAlgorithm;
28
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
29
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//这是策略模式的典型特征
30
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public double GetResult(double price, int quantity)
31
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return billingAlgorithm.getBillingResult(price, quantity);
33
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
34
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
35
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
36
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
好,算法完成了,下面介绍客户端,界面如图2所示:
图2. 商场收银系统界面
下面看一下,确定按钮后面的代码:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
private void btnOK_Click(object sender, EventArgs e)
{
\\只需要知道这个Context类,实例化它;
Billing billing = new Billing(cbxBillingType.Text);
\\并调用它提供的方法,即可完成我们需要的功能。
double charge = billing.GetResult(double.Parse(txtPrice.Text),
int.Parse(txtQuantity.Text));
totalCash = totalCash + charge;
string itemShow = "单价:"+txtPrice.Text
+ "\t数量:"+txtQuantity.Text +
".\t实收:"+ charge.ToString()
+ "\t"+cbxBillingType.Text;
list.Items.Add(itemShow);
lblSum.Text = totalCash.ToString();
}
相关文章推荐
- SpringMVC教程(五)用Spring的邮件封装类JavaMailSenderImpl发送邮件
- Spring MVC拦截器+注解方式实现防止表单重复提交
- 一个java的DES加解密类转换成C#
- Java中的Vector和ArrayList的比较
- AJAX请求和响应
- Java集合深入学习总结-HashMap
- eclipse的console总是出现如下的错误“Adb connection Error:远程主机强迫关闭了一个现有的连接”
- Java基础11 对象引用
- [转载]java的几种对象(PO,VO,DAO,BO,POJO)解释
- java,String做参数实参值不变,equals与==浅析
- Java集合深入学习总结-HashSet
- Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Multiple representations of the same entity解决方法
- [转]JAVA中Action层, Service层 ,modle层 和 Dao层的功能区分
- java正则表达式 过滤特殊字符的正则表达式
- Spark Streaming+kafka+eclipse编程
- Java基础10 接口的继承与抽象类
- Spring快速入门
- 设计模式 过滤器模式
- Java集合深入学习总结-LinkedHashSet
- Spring的@ModelAttribute注解