设计模式之责任链应用
将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递。从而避免请求的
发送者和接受者之间的耦合关系。链上的对象逐个判断是否有能力处理该请求,如果能则就处理,如果不能,则传给链上的下一个对象。直到有一个对象处理它为止。
设计模式的应用
设计模式在架构设计中用的恰当,能起到画龙点睛的作用,但如果用的不恰当,反而成为叶公好龙,在后续维护中增加成本,并且没有收益,因此设计模式的引入需要我们好好掂量掂量!
应用场景
以前的一个项目中,大致场景如下:我们需要对装修中的建筑模型进行拆分,并且按照拆分的零件以及一系列规则按照顺序进行排序,并输出为工人可以按时间进行施工的工作,规则是需要根据任务、工作面、工人资源、工种工序要求等一系列条件进行限制和制约,使得保持一个工作面上最好有一个任务持续进行。
设计
根据调度前期需求调研,此处变化集频繁和变更与一身,因此,此处选择职责链模式和工作流引擎模式解决该需求的设计。职责链模式集中设计各个类要加工的素材,加工后交付给下一个职责类进行处理,无需关心下一个职责类是谁;职责链整体组装依赖外部调用者,外部调用者决定采用哪几个职责类,什么顺序进行组装,以方便需求变更后的处理,而无需影响下一个功能点。流程引擎封装调度状态的变迁,状态需求的变更不再依赖单纯的编程代码,而仅需要更改流程图即可。这里着重介绍下职责链的设计,工作流设计后续有时间再写文章。
职责类均继承自BaseResponsibility抽象基类,抽象类实现了职责链的组装,职责链的执行、职责链的链式调用、职责链共有信息的传递等功能。继承的职责类只需要完成相应的功能即可。DispatchBootstrap职责类完成了所有数据的加载工作;TaskGlobalFilter职责类完成任务的过滤工作;WorkGroupStat完成工作组的效率等的统计工作;WorkGlobalFilter职责类完成工作组的过滤工作;WorkGroupWeightCalc职责类完成每个任务下各个小组的权重计算工作;AssignTaskCore职责类完成指派工作的工作;BizDataCleaning职责类完成业务数据的清理工作;GenerateTaskOrder职责类完成任务单下发,短信发送等一系列工作。
基类代码
基类是一个抽象类,需要继承实现。
/// <summary>
/// 职责类基类 ,可参考职责设计模式
/// 所有的职责类均继承该类,职责类可设置下一个需要处理的职责类
/// 在职责类调用时,只需调用 ExecuteTask 方法即可
/// </summary>
public abstract class BaseResponsibility
{
protected OperateInfo _oInfo;
protected BaseResponsibility responsibility;
protected ILogger Log = LogManager.GetLogger("biz");
/// <summary>
/// 执行关联数据
/// </summary>
public ProcessContext Context { get; set; }
public BaseResponsibility GetResponsibility()
{
return responsibility;
}
/// <summary>
/// 设置接下来的职责类,这样就形成了一个职责链,
/// 职责类被调用后,会沿职责链依次调用
/// </summary>
/// <param name="responsibility"></param>
/// <returns></returns>
public BaseResponsibility SetResponsibility(BaseResponsibility responsibility)
{
this.responsibility = responsibility;
return this.responsibility;
}
/// <summary>
/// 子类需要实现的处理方法
/// </summary>
/// <returns></returns>
protected abstract void Execute();
/// <summary>
/// 执行工序资源的处理
/// </summary>
/// <param name="context"></param>
/// <param name="provider"></param>
/// <param name="oInfo"></param>
/// <returns></returns>
public ProcessContext ExecuteProcess(ProcessContext context, OperateInfo oInfo)
{
_oInfo = oInfo;
Context = context;
try
{
Execute();
}
catch (Exception e)
{
Trace.WriteLine(string.Format("{0}执行异常,已跳过!{1}", this.GetType().Name, e.Message));
if (Log != null)
{
Log.Error(this.GetType().Name + " 执行失败,", e);
}
}
if (this.responsibility != null)
{
return this.responsibility.ExecuteProcess(Context, oInfo);
}
else
{
return Context;
}
}
}
上下文
上下文是职责链需要传递的内容,定义如下:
/// <summary>
/// 工序上下文
/// </summary>
public class ProcessContext
{
/// <summary>
/// 工序全局(参数)信息
/// </summary>
public ProcessBootInfo ProcessBootInfo { get; set; }
public ProcessInfo ProcessInfo { get; set; }
/// <summary>
/// 项目ID
/// </summary>
public int ProjectId { get; set; }
/// <summary>
/// 分项ID
/// </summary>
public int SubProjectId { get; set; }
/// <summary>
/// 公司ID
/// </summary>
public int CompanyId { get; set; }
/// <summary>
/// 项目结构EpsCode
/// </summary>
public string EpsCode { get; set; }
/// <summary>
/// skp拆分模型产生的数据
/// </summary>
public List<PmSKPTasktInfo> DsSkpTask { get; set; }
/// <summary>
/// 中间信息
/// </summary>
public Dictionary<string, object> BagInfo { get; set; }
/// <summary>
/// 任务执行结果
/// </summary>
public ProcessResult ProcessResult { get; set; }
/// <summary>
/// 公司Code
/// </summary>
public string CompanyCode { get; set; }
}
结语
链的好处是可以自由组合,每个链和其他均为松耦合。唯一的处理数据来源于上下文。因此链的开发也可以划分为多个开发者进行。调用者就比较简单了,组装链即可。
在此我向大家推荐一个微服务架构学习交流群。交流学习QQ群号:864759589 里面会分享一些资深架构师录制的视频录像:高并发、高性能、分布式、微服务架构的原理,分布式架构等这些成为架构师必备的知识体系。