策略模式
策略模式
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。

- 环境(Context)角色:持有一个Strategy类的引用。
- 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
适用场景:
对外实现的方法接口都一样,但是具体内部的算法不一样
比如:不同厂家提供的外接读卡设备A和设备B。所有的设备的操作步骤基本都是以下步骤:
- 连接设备
- 读数据
- 写数据
- 修改密钥
- 断开设备
我们需要写入、保存、读取的数据对客户来说是一样的,只是分配给客户的外接读卡设备有可能是设备A或者设备B。
客户首先选择手头上的设备类型:

客户读取和写入数据的界面

如果不考虑设计模式,或易扩展模式。我们的通常写法是根据用户在界面上选择的checkBox。然后在代码里比做判断。
可能出现在后台的代码如下:
1 var 设备A实例=new 设备A(); 2 var 设备B实例 = new 设备A(); 3 //连接设备 4 private void button5_Click(object sender, EventArgs e) 5 { 6 if (checkBox1.Checked) 7 { 8 //调用设备A的连接设备方法 9 设备A实例.ConnectDriver(); 10 } 11 else 12 { 13 //调用设备B的连接设备方法 14 设备B实例.ConnectDriver(); 15 } 16 } 17 //读数据 18 private void button2_Click(object sender, EventArgs e) 19 { 20 if (checkBox1.Checked) 21 { 22 //调用设备A的读数据方法 23 设备A实例.ReadData(); 24 } 25 else 26 { 27 //调用设备B的读数据方法 28 设备B实例.ReadData(); 29 } 30 } 31 32 //写数据 33 private void button3_Click(object sender, EventArgs e) 34 { 35 if (checkBox1.Checked) 36 { 37 //调用设备A的写数据方法 38 设备A实例.WriteData(); 39 } 40 else 41 { 42 //调用设备B的写数据方法 43 设备B实例.WriteData(); 44 } 45 46 } 47 48 //断开设备 49 private void button4_Click(object sender, EventArgs e) 50 { 51 if (checkBox1.Checked) 52 { 53 //调用设备A的断开设备方法 54 设备A实例.DisconnectDriver(); 55 } 56 else 57 { 58 //调用设备B的断开设备方法 59 设备B实例.DisconnectDriver(); 60 } 61 }
可以看到,每一步和设备的交互都需要有判断。大量的if..else..,如果其中再有相关复杂的业务逻辑,代码很难看。如果以后再新增其他读卡设备C,读卡设备D....代码维护难度大大的增加。
这里我们考虑使用“策略模式”。
IDriverCard对应于-》抽象策略(Strategy):在我们当前情况下是对于读卡设备。一个抽象的读卡设备
1 public interface IDriverCard 2 { 3 /// <summary> 4 /// 连接设备 5 /// </summary> 6 /// <param name="ComPort"></param> 7 /// <param name="Botelv"></param> 8 /// <returns></returns> 9 bool ConnectDriver(string ComPort, string Botelv); 10 /// <summary> 11 /// 断开设备 12 /// </summary> 13 /// <returns></returns> 14 bool DisconnectDriver(); 15 /// <summary> 16 /// 读数据 17 /// </summary> 18 /// <returns></returns> 19 bool ReadData(ClsDriverCardInfo DriverCardInfo); 20 /// <summary> 21 /// 写数据 22 /// </summary> 23 /// <param name="CardInfo"></param> 24 /// <returns></returns> 25 bool WriteData(ClsDriverCardInfo CardInfo); 26 /// <summary> 27 /// 修改密钥 28 /// </summary> 29 /// <returns></returns> 30 bool KeyInit(); 31 }
设备A对应于-》具体策略
1 public class 设备A : IDriverCard 2 { 3 public bool ConnectDriver(string ComPort, string Botelv) 4 { 5 int rst = MasterRDInterface.rf_init_com(Convert.ToInt16(ComPort) + 1, ClsConvertHelper.ToInt32(Botelv, 9600)); 6 if (rst != 0) 7 { 8 return false; 9 } 10 return true; 11 } 12 13 public bool DisconnectDriver() 14 { 15 int rst = 0; 16 rst = MasterRDInterface.rf_ClosePort(); 17 if (rst != 0) 18 return false; 19 return true; 20 } 21 22 public bool ReadData(ClsDriverCardInfo DriverCardInfo) 23 { 24 //具体实现,略 25 } 26 27 /// <summary> 28 /// 写数据 29 /// </summary> 30 /// <param name="CardInfo"></param> 31 /// <returns></returns> 32 public bool WriteData(ClsDriverCardInfo CardInfo) 33 { 34 //具体实现,略 35 } 36 37 /// <summary> 38 /// 修改密钥 39 /// </summary> 40 /// <returns></returns> 41 public bool KeyInit() 42 { 43 //具体实现,略 44 } 45 46 }
设备B对应于-》具体策略
1 public class 设备B : IDriverCard 2 { 3 private int icdev = 0; 4 5 public bool ConnectDriver(string ComPort, string Botelv) 6 { 7 icdev = IccardInterface.ic_init(Convert.ToInt16(ComPort), ClsConvertHelper.ToInt32(Botelv, 9600)); //连接设备 8 if (icdev > 0) 9 { 10 byte[] ver = new byte[20]; 11 int passResult = IccardInterface.srd_ver(icdev, 18, ver); //ic_init返回值大于0不一定连接成功,然后对读写器进行操作来确定是否连接成功,如读硬件版本号 12 if (passResult == 0) 13 { 14 IccardInterface.dv_beep(icdev, 30); 15 return true; 16 } 17 else 18 { 19 return false; 20 } 21 } 22 else 23 { 24 return false; 25 } 26 } 27 28 public bool DisconnectDriver() 29 { 30 try 31 { 32 if (icdev > 0) 33 { 34 IccardInterface.ic_exit(icdev); 35 } 36 return true; 37 } 38 catch 39 { 40 return false; 41 } 42 } 43 44 public bool ReadData(ClsDriverCardInfo DriverCardInfo) 45 { 46 //具体实现,略 47 } 48 49 /// <summary> 50 /// 写数据 51 /// </summary> 52 /// <param name="CardInfo"></param> 53 /// <returns></returns> 54 public bool WriteData(ClsDriverCardInfo CardInfo) 55 { 56 //具体实现,略 57 } 58 59 /// <summary> 60 /// 修改密钥 61 /// </summary> 62 /// <returns></returns> 63 public bool KeyInit() 64 { 65 //具体实现,略 66 } 67 }
ClsDriverCardHelper对应于-》环境(Context)角色
1 public class ClsDriverCardHelper 2 { 3 public IDriverCard DriverCard { get; set; } 4 public ClsDriverCardHelper(IDriverCard drivercard) 5 { 6 DriverCard = drivercard; 7 } 8 9 public bool ConnectDriver(string ComPort, string Botelv) 10 { 11 return DriverCard.ConnectDriver(ComPort, Botelv); 12 } 13 14 public bool DisconnectDriver() 15 { 16 return DriverCard.DisconnectDriver(); 17 } 18 19 public bool ReadData(ClsDriverCardInfo DriverCardInfo) 20 { 21 return DriverCard.ReadData(DriverCardInfo); 22 } 23 24 public bool WriteData(ClsDriverCardInfo CardInfo) 25 { 26 return DriverCard.WriteData(CardInfo); 27 } 28 29 public bool KeyInit() 30 { 31 return DriverCard.KeyInit(); 32 } 33 }
可以看到,具体设备A和具体设备B,里面关于连接设备ConnectDriver和关闭设备DisconnectDriver的实现代码片段(其他方法略过)都是不同的,但对外提供的接口是一致的。
最终在界面上的代码如下:
1 private ClsDriverCardHelper DriverCardHelper; 2 3 //初始 4 private void button1_Click(object sender, EventArgs e) 5 { 6 if (checkBox1.Checked) 7 { 8 DriverCardHelper = new ClsDriverCardHelper(new 设备A()); 9 } 10 else 11 { 12 DriverCardHelper = new ClsDriverCardHelper(new 设备B()); 13 } 14 15 } 16 17 //连接设备 18 private void button5_Click(object sender, EventArgs e) 19 { 20 21 DriverCardHelper.ConnectDriver(StrCom.ToString(), Botelv) 22 } 23 //读数据 24 private void button2_Click(object sender, EventArgs e) 25 { 26 DriverCardHelper.ReadData(); 27 } 28 29 //写数据 30 private void button3_Click(object sender, EventArgs e) 31 { 32 DriverCardHelper.WriteData(UiIcCardInfo); 33 34 } 35 36 //断开设备 37 private void button4_Click(object sender, EventArgs e) 38 { 39 DriverCardHelper.DisconnectDriver(); 40 }
可以看到,我们之前的if...else...已经不再出现了。代码清晰简洁。
以后如果还需要增加设备C、设备B。那么只要增加具体策略(设备C类,设备D类)并实现抽象策略IDriverCard的接口,由于对外的接口是保持不变的,所以原有的业务逻辑代码是不用修改的。
~结束
posted on 2017-05-19 14:07 Shine-Zhong 阅读(210) 评论(0) 收藏 举报
浙公网安备 33010602011771号