策略模式

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

 

  • 环境(Context)角色:持有一个Strategy类的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

适用场景:
对外实现的方法接口都一样,但是具体内部的算法不一样
比如:不同厂家提供的外接读卡设备A和设备B。所有的设备的操作步骤基本都是以下步骤:

  1. 连接设备
  2. 读数据
  3. 写数据
  4. 修改密钥
  5. 断开设备

我们需要写入、保存、读取的数据对客户来说是一样的,只是分配给客户的外接读卡设备有可能是设备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)    收藏  举报

导航