前言:前阵子拖着没弄完的机房重构这次重新完善,发现有一些设计模式并没有体现出来,所以今天加了一个职责链模式
机房重构中,上机的过程需要经过诸多判断,因此这个过程使用职责链模式是完全可以的。
我们先梳理一下逻辑:上机之前需要先判断该卡号是否存在,之后判断卡号的余额,最后判断该卡是否正在上机,最后执行上机操作。(这是本人的思路,仅供参考)按照这个思路,我们往下进行。
首先建立职责链项目,新建引用(Entity、IDAL、DAL,仅供参考),建立以下类
Handler类是一个抽象类,用来被子类重写和设置子类方法的后继方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace ChainModel
{
public abstract class Handler
{
protected _5.IDAL.OnlineIDAL idal;
protected Handler successor;
//构造函数
public Handler(_5.IDAL.OnlineIDAL idal)
{
this.idal = idal;
}
//设置下一个处理对象
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
//抽象处理方法,使子类重写它,实现不同行为,多态的原理
public abstract void HandlerRequest(_7.Entity.OnlineEntity cardid);
}
}
*设置Handler的参数为IDAL层是为了能够调用DAL层的方法获取相应参数进行判断,而又保证代码的低耦合。
下一步建立Chain_IsCardid类,继承Handler类,在里面写好逻辑判断。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace ChainModel
{
public class Chain_IsCardid:Handler
{
public Chain_IsCardid(_5.IDAL.OnlineIDAL idal) : base(idal) { }
//重写父类方法,体现多态
public override void HandlerRequest(_7.Entity.OnlineEntity cardid)
{
//调用IDAL层查询卡号的方法
DataTable iscardid = idal.ViewCardID(cardid);
if(iscardid.Rows.Count == 0)
{
throw new Exception("没有这个卡号!");
}
else
{
successor.HandlerRequest(cardid);
}
}
}
}
之后建立Chain_IsCash类,判断是否余额不足
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _7.Entity;
using System.Data;
namespace ChainModel
{
public class Chain_IsCash:Handler
{
public Chain_IsCash(_5.IDAL.OnlineIDAL idal) : base(idal) { }
public override void HandlerRequest(_7.Entity.OnlineEntity cardid)
{
//调用IDAL层查询余额的方法与基本信息的方法
DataTable iscash = idal.ViewCardCash(cardid);
DataTable table = idal.DALViewLimitCash(cardid);
if(Convert.ToDouble(iscash.Rows[0]["cash"]) < Convert.ToDouble(table.Rows[0]["limitCash"]))
{
throw new Exception("余额不足!");
}
else
{
successor.HandlerRequest(cardid);
}
}
}
}
下一步建立Chain_IsOnline,判断是否上机
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _7.Entity;
using System.Data;
namespace ChainModel
{
public class Chain_IsOnline:Handler
{
public Chain_IsOnline(_5.IDAL.OnlineIDAL idal) : base(idal) { }
public override void HandlerRequest(_7.Entity.OnlineEntity cardid)
{
DataTable table = idal.ViewCardState(cardid);
if(table.Rows.Count > 0)
{
throw new Exception("该用户正在上机!");
}
else
{
return;
}
}
}
}
本来开始是想把上机的操作也放到职责链中,但因为引用的问题(不知道为什么不能引用UI层,不能引用就不能调用UI层的控件进行操作),所以没有放进来。机房合作的时候注意这个问题!
职责链弄好之后,我们在BLL层调用职责链模式,并设定后继方法的顺序链与开始执行的位置:
//职责链模式 上机,新增职责链模式上机方法
public DataTable Online_model(_7.Entity.OnlineEntity cardid)
{
//实例化工厂层
_4.Factory.OnlineFactory onlineFactory = new _4.Factory.OnlineFactory();
_5.IDAL.OnlineIDAL idal = onlineFactory.CreateStudent();
//职责链模式
//1.创建具体处理对象,实例化时把“处理的具体执行者”-idal传过去
ChainModel.Chain_IsCardid iscardid = new ChainModel.Chain_IsCardid(idal);
ChainModel.Chain_IsCash iscash = new ChainModel.Chain_IsCash(idal);
ChainModel.Chain_IsOnline isonline = new ChainModel.Chain_IsOnline(idal);
//2.从底层设置上一级,逐级设置
iscardid.SetSuccessor(iscash);
iscash.SetSuccessor(isonline);
//3.从链的底层开始执行
iscardid.HandlerRequest(cardid);
return idal.ViewCardState(cardid);
}
之后在Facade层调用B层减少耦合,最后在U层调用F层的语句,加入上机后需要的操作,就完成了!
public class OnlineFacade
{
//实例化BLL层
_3.BLL.OnlineBLL onlineBLL = new _3.BLL.OnlineBLL();
//调用B层职责链上机方法
public DataTable FacadeOnline(_7.Entity.OnlineEntity cardid)
{
DataTable table = onlineBLL.Online_model(cardid);
return table;
}
}
private void btnonline_Click(object sender, EventArgs e)
{
//调用F层职责链方法
DataTable online = onlineFacade.FacadeOnline(onlineStudent);
timerdynamicdetect.Enabled = true;//实时监控时钟开始运行
timerdynamictime.Enabled = true;//动态时间时钟开始运行
lblondate.Text = DateTime.Now.ToString("yyyy-MM-dd");//lblondate获取当前日期
lblontime.Text = DateTime.Now.ToString("HH:mm:ss");//lnlontime获取当前时间
//将上机时间日期与用户类型传给实体层
onlineStudent.State = "上机";
onlineStudent.OnDate = Convert.ToDateTime(lblondate.Text);
onlineStudent.OnTime = Convert.ToDateTime(lblontime.Text);
//余额与消耗时间都先为0
lblconsumetime.Text = "0";
lblconsumecash.Text = "0";
//下机时间与日期也变为0
lbloffdate.Text = "";
lblofftime.Text = "";
//调用外观层方法-修改用户上机状态
onlineFacade.ModifyOnlineState(onlineStudent);
MessageBox.Show("上机成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
//下机按钮可用
btnoffline.Enabled = true;
}
结尾:之前单纯学习设计模式的时候都能理解,但实际应用,还是在又有Class类又有Winform类的七层中使用还是会阻碍重重,比如引用、不同类型的转换,就比如我这里为了省事,几个子类职责链内返回的参数都是DataTable类。这些如果不琢磨透的话,一开始很容易吃大亏的。