项目重构--使用策略模式
大家先看下下面这段代码有什么感受?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.ServiceModel;
using PCI_ClassLibrary;
using System.Windows.Threading;
using Oland.HIP.Common.Entities;
using Oland.HSS.Common;
using Oland.HIP.Common.Enums;
using System.Windows.Media.Imaging;
namespace Oland.HSS.InHospital
{
public class BaseSwingCardWindow : BaseWindow
{
//检测读卡器是否打开
public bool IsOpened { get; set; }
//刷卡的模块
public Modules myModule { get; set; }
//刷卡类型
public CardTypeMode CardType;
//刷卡定时器
DispatcherTimer SwingTimer;
//切换背景
//public BitmapImage bgImg = new BitmapImage(new Uri("../Picture/main/yhk.png",UriKind.Relative));
public BitmapImage bgImg;
//切换提示信息
public string tipMsg = "请按提示刷您的签约\n银行卡";
public BaseSwingCardWindow() { }
public BaseSwingCardWindow(CardTypeMode CardType)
{
//Load事件播放语音
this.Loaded += new RoutedEventHandler(BaseSwingCardWindow_Loaded);
//窗口关闭,停止定时器
this.Closed += (object sender, EventArgs e) => { this.SwingTimer.IsEnabled = false; };
SwingTimer = new DispatcherTimer();
SwingTimer.Interval = TimeSpan.FromSeconds(1);
SwingTimer.Tick += new EventHandler(SwingTimer_Tick);
SwingTimer.IsEnabled = true;
this.CardType = CardType;
string strError = "";
//硬件检测显示进度条
Common.CommWindow.BeginProgressBar("",0);
if (CardType == CardTypeMode.BankCard || CardType == CardTypeMode.MedicalCard)
{
if (Oland.HSS.Common.OperationPCI.CheckDevice(out strError, DeviceName.ReadCard3in1))
{
IsOpened = true;
string error;
Oland.HSS.Common.OperationPCI.EnableCardIn(out error);
//切换为就诊卡刷卡动画
if (CardType == CardTypeMode.MedicalCard)
{
bgImg = new BitmapImage(new Uri("../Pictures/main/jzk.png", UriKind.Relative));
tipMsg = "请按提示刷您的就诊卡";
}
}
else
{
IsOpened = false;
Common.CommWindow.EndProgressBar();
Common.CommWindow.ShowDialogTip("读卡器故障", strError);
return;
}
}
else
{
if (HSS.Common.OperationPCI.CheckDevice(out strError, DeviceName.IDCard))
{
//切换身份证背景
bgImg = new BitmapImage(new Uri("../Pictures/main/sfz.png", UriKind.Relative));
tipMsg = "请按提示刷您的身份证";
}
else
{
IsOpened = false;
Common.CommWindow.EndProgressBar();
Common.CommWindow.ShowDialogTip("","身份证读卡器故障,请联系柜台!");
return;
}
}
//检测小票打印机
if (!HSS.Common.OperationPCI.CheckDevice(out strError, DeviceName.Printer))
{
IsOpened = false;
Common.CommWindow.EndProgressBar();
Common.CommWindow.ShowDialogTip("","小票打印机故障,请联系柜台!");
}
Common.CommWindow.EndProgressBar();
}
void BaseSwingCardWindow_Loaded(object sender, RoutedEventArgs e)
{
switch (CardType)
{
case CardTypeMode.IDCard:
HSS.Common.OperationPCI.SetVoicesUrl("Voices/请刷二代身份证.wav");
break;
case CardTypeMode.MedicalCard:
HSS.Common.OperationPCI.SetVoicesUrl("Voices/请刷就诊卡.wav");
break;
case CardTypeMode.BankCard:
HSS.Common.OperationPCI.SetVoicesUrl("Voices/请刷签约银行卡.wav");
break;
case CardTypeMode.MedicalInsuranceCard:
break;
case CardTypeMode.HealthCard:
break;
default:
break;
}
}
//定时刷新
void SwingTimer_Tick(object sender, EventArgs e)
{
if (SwingCarding(CardType))
{
SwingTimer.IsEnabled = false;
TransWin();
}
}
//用于基类重写,实现刷卡后跳转功能
public virtual void TransWin()
{
}
/// <summary>
/// 刷卡
/// </summary>
/// <param name="type">刷卡类型</param>
public bool SwingCarding(CardTypeMode type)
{
string strError = null;
CardInfo cardInfo = new CardInfo();
switch (type)
{
case CardTypeMode.IDCard://刷身份证
IDCard_XZX_DKQ116D.IDCardData IDCardInfo = new IDCard_XZX_DKQ116D.IDCardData();
if (OperationPCI.ReadIDCard(ref IDCardInfo, ref strError))
{
WinContext.SetData<IDCard_XZX_DKQ116D.IDCardData>("IDCardData", IDCardInfo);
return true;
}
else
{
// Common.CommWindow.ShowDialogTip("错误信息", strError, true);
}
break;
case CardTypeMode.BankCard://刷签约银行卡
string bdCardNo = OperationPCI.ReadMagneticCard();
if (bdCardNo != "")
{
cardInfo.CardNum = bdCardNo;
cardInfo.CardType = Oland.HIP.Common.Enums.CardTypeMode.BankCard;
string
result = GetPatientInfoAndSave(cardInfo);
if (result == "")
return true;
else
{
Common.CommWindow.ShowDialogTip("", result, false);
HSS.Common.OperationPCI.BackCard();
return false;
}
}
break;
case CardTypeMode.MedicalCard://刷就诊卡
string mcCardNo = OperationPCI.ReadMagneticCard();
if (mcCardNo != "")
{
cardInfo.CardNum = mcCardNo;
cardInfo.CardType = Oland.HIP.Common.Enums.CardTypeMode.MedicalCard;
string result = GetPatientInfoAndSave(cardInfo);
if (result == "")
return true;
else
{
Common.CommWindow.ShowDialogTip("", result, false);
HSS.Common.OperationPCI.BackCard();
return false;
}
}
break;
default:
break;
}
return false;
}
//错误信息
static ErrorMessageInfo errInfo;
/// <summary>
/// 根据卡号获取病人信息并存储
/// </summary>
/// <param name="cardInfo">卡信息</param>
/// <param name="isReg">是否为登记,登记从基础服务取数据,其他从住院服务取数据</param>
/// <returns>成功返回“”</returns>
public string GetPatientInfoAndSave(CardInfo cardInfo)
{
string error = "";
Common.CommWindow.BeginProgressBar("",0);
try
{
//根据卡号获取病人信息
if (myModule == Modules.Register)
{
PatientInfo patientInfo = HIPServices.BasicServiceClient.GetPatientInfoByCard(out errInfo, cardInfo);
if (patientInfo != null)
{
WinContext.SetData<PatientInfo>("PatientInfo", patientInfo);
}
else
error =cardInfo.CardType==CardTypeMode.BankCard? "非签约银行卡,请更换就银行卡重试":"非本院就诊卡,请更换后重试";
}
else
{
InHospitalPatientInfo patientInfo = HIPServices.InHospitalServiceClient.GetHospitalPatientInfoByCard(out errInfo, cardInfo);
if (patientInfo != null)
{
WinContext.SetData<InHospitalPatientInfo>("InHospitalPatientInfo", patientInfo);
}
else
{
error = cardInfo.CardType == CardTypeMode.BankCard ? "非签约银行卡,请更换就银行卡重试" : "非本院就诊卡,请更换后重试";
}
}
}
catch (Exception ex)
{
error = "连接服务失败,请到其它自助设备或窗口办理";
}
Common.CommWindow.EndProgressBar();
return error;
}
}
代码凌乱,层次不清晰,过多的判断,扩展性差.....真的快看不下去了.所以决定重构下.因为最近在学设计模式,仔细分析下,这不正好策略模式很像吗?
先看下策略模式的组成:
——抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
——具体策略角色:包装了相关的算法和行为。
——环境角色:持有一个策略类的引用,最终给客户端调用。
再看下策略模式的定义:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
好,我们对策略模式稍微有了了解,那我们开始重构这段代码:
首先讲下这段代码要实现的功能,他主要是刷卡功能的实现,有就诊卡,银行卡,医保卡等,每种卡对应不同的刷卡器,同时对应不同的信息提示与背景显示等.
我们先定义一个刷卡接口,将需要改变的信息都给抽象出来.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oland.HIP.Common.Enums;
using Oland.HIP.Common.Entities;
namespace Oland.HSS.InHospital.SwipingCard
{
public interface ISwipingCard
{
/// <summary>
/// 卡名称
/// </summary>
string CardName { get; }
/// <summary>
/// 卡类型
/// </summary>
CardTypeMode CardType { get; }
/// <summary>
/// 界面信息提示
/// </summary>
string TipMsg { get; }
/// <summary>
/// 背景图片路径
/// </summary>
string BackgroundImagePath { get; }
/// <summary>
/// 检测硬设
/// </summary>
/// <returns></returns>
bool CheckDevice();
/// <summary>
/// 播放语音提示
/// </summary>
void PlayVoice();
/// <summary>
/// 刷卡
/// </summary>
/// <returns></returns>
CardInfo SwipingCard();
/// <summary>
/// 将数据存储到缓存
/// </summary>
/// <returns></returns>
string SaveData();
}
}
下面分别是各个具体的刷卡类型
银行卡:
class SwipingBankCard : ISwipingCard
{}
就诊卡:
class SwipingMedicalCard:ISwipingCard
{
}
等等^........
下面是文件结构,如果在增加相应的类就行了
下面咱们再把最上面的代码再看下:
public class BaseSwingCardWindow : BaseWindow
{
//检测读卡器是否打开
public bool IsOpened { get; set; }
//刷卡的模块
public Modules myModule { get; set; }
//刷卡定时器
DispatcherTimer SwingTimer;
public BitmapImage bgImg;
//切换提示信息
public string tipMsg = "请按提示刷您的签约\n银行卡";
public BaseSwingCardWindow() { }
public BaseSwingCardWindow(ISwipingCard swipingCard)
{
Common.CommWindow.BeginProgressBar("", 1000);
bgImg = new BitmapImage(new Uri(swipingCard.BackgroundImagePath, UriKind.Relative));
tipMsg = swipingCard.TipMsg;
//Load事件播放语音
this.Loaded += (s, e) => swipingCard.PlayVoice();
//窗口关闭,停止定时器
this.Closed += (s, e) => this.SwingTimer.IsEnabled = false;
//创建定时器间隔读取卡号
CreateDispatcherTimer(swipingCard);
string strError;
//检测读卡器
if (swipingCard.CheckDevice())
{
if (HSS.Common.OperationPCI.CheckDevice(out strError, DeviceName.Printer))
{
IsOpened = true;
SwingTimer.IsEnabled = true;
}
else
{
IsOpened = false;
Common.CommWindow.ShowDialogTip("", "小票打印机故障,请联系柜台!");
}
}
else
{
IsOpened = false;
Common.CommWindow.ShowDialogTip("", string.Format("{0}故障,请联系柜台!", swipingCard.CardName));
}
Common.CommWindow.EndProgressBar();
}
private void CreateDispatcherTimer(ISwipingCard swipingCard)
{
SwingTimer = new DispatcherTimer();
SwingTimer.Interval = TimeSpan.FromSeconds(1);
SwingTimer.Tick += (s, e) =>
{
CardInfo cardInfo = swipingCard.SwipingCard();
if (!string.IsNullOrEmpty(cardInfo.CardNum))
{
SwingTimer.IsEnabled = false;
string msg = GetPatientInfoAndSave(cardInfo);
if (msg != "")
{
Common.CommWindow.ShowDialogTip("", msg);
HSS.Common.OperationPCI.BackCard();
}
else
{
SwingTimer.IsEnabled = false;
TransWin();
}
}
};
}
//用于基类重写,实现刷卡后跳转功能
public virtual void TransWin()
{
}
//错误信息
static ErrorMessageInfo errInfo;
/// <summary>
/// 根据卡号获取病人信息并存储
/// </summary>
/// <param name="cardInfo">卡信息</param>
/// <param name="isReg">是否为登记,登记从基础服务取数据,其他从住院服务取数据</param>
/// <returns>成功返回“”</returns>
public string GetPatientInfoAndSave(CardInfo cardInfo)
{
//刷身份证不需要从数据库读取数据
if (cardInfo.CardType == CardTypeMode.IDCard)
{
return"";
}
string error = "";
Common.CommWindow.BeginProgressBar("", 0);
try
{
//根据卡号获取病人信息
if (myModule == Modules.Register)
{
PatientInfo patientInfo = HIPServices.BasicServiceClient.GetPatientInfoByCard(out errInfo, cardInfo);
if (patientInfo != null)
{
WinContext.SetData<PatientInfo>("PatientInfo", patientInfo);
}
else
error = cardInfo.CardType == CardTypeMode.BankCard ? "非签约银行卡,请更换就银行卡重试" : "非本院就诊卡,请更换后重试";
}
else
{
InHospitalPatientInfo patientInfo = HIPServices.InHospitalServiceClient.GetHospitalPatientInfoByCard(out errInfo, cardInfo);
if (patientInfo != null)
{
WinContext.SetData<InHospitalPatientInfo>("InHospitalPatientInfo", patientInfo);
}
else
{
error = cardInfo.CardType == CardTypeMode.BankCard ? "非签约银行卡,请更换就银行卡重试" : "非本院就诊卡,请更换后重试";
}
}
}
catch (Exception ex)
{
error = "连接服务失败,请到其它自助设备或窗口办理";
}
Common.CommWindow.EndProgressBar();
return error;
}
}
重构后代码量减少了将近一半以上,而且更容易扩展了,可读性也高了许多^,另外这里的我将接口在构造函数中使用,而更常用的方式是把ISwipingCard设为属性
怎样调用:
SwipingCard.SwipingBankCard sbc = new SwipingCard.SwipingBankCard();
WinQuerySwingCard winSwing = new WinQuerySwingCard(sbc);
if (winSwing.IsOpened)
{
winSwing.myModule = Modules.Print;
winSwing.Show();
this.Close();
}
else
{
winSwing.Close();
}
Ps:这里WinQuerySwingCard 继承自BaseSwingCardWindow