`

FoxBPM 系列之-设计模式、OO原则

阅读更多
时光荏苒,不忘初心,勿在浮沙筑高台!继续每周一篇的FoxBPM 系列!
流程引擎永远不可能独立的面向客户,它必须通过组建的方式集成于平台和客户交互。既然是组件那么我们就需要将其架构设计的具有弹性、可重用性、平台关联性、和其他组件的互联互通性等等。那么什么样的架构才能达到这样的高度?什么样的设计才能满足这样的要求?凡此种种。本周就带着这些疑问跟大家介绍一下FoxBPM流程引擎的架构设计中所遵循的OO原则和运用的设计模式。
 
首先看一下整个流程引擎设计所遵循的一些OO原则:
1、单一职责原则
     FoxBPM引擎的外层service具体实现都由Command命令封装之,和ACTIVITI相似,Command设计模式的引入将流程运转中的功能进行模块化粒度化,职责单一化。每个模块只负责其中一件事,这样系统进行功能扩展时就更加容易,解耦的更加彻底。我们生活中也是如此,如果专心做一件事,这件事肯定能做的很好。正所谓“样样精通,样样稀松”就是这个道理。整个系统的功能扩展都得益于这样的模块化设计。
 
2、接口隔离原则
     整个流程的运转是基于一个引擎虚拟机的,而虚拟机的运行基于令牌算法(我们系统的微内核由令牌驱动,和JBPM类似,不知道令牌算法的请看Petri Net网,百度之。可以说Petri Net是很多流程语言的父亲),所以令牌算法模块结构设计的优良与否直接影响到整个流程的运转。由于令牌支撑的是整个流程引擎,所以令牌需要面对不同的客户不同的功能模块,比如说事件监听执行、节点跳转、引擎表达式执行等等,针对这些问题流程引擎设计了多个不同的接口代表令牌所要演示的角色,将令牌的功能宽窄化。这样令牌就可以将其自身的职责功能发挥的尽善尽美了!
 
3、开闭原则
    开闭原则属于几大原则中最高级最抽象的原则,只可意会不可言传!美其名曰:“对变更关闭、对扩展开放”。人类在进步,市场在变化,客户的需求也无时无刻不在变化,为了达到快速响应的目的,这就要求我们将程序设计的更容易扩展。虽然工作流领域相对稳定,但是我们FoxBPM引擎架构设计时依然遵循这样的高级原则。比如BPMN模型解析转换模块、流程引擎装配模块,基于该原则的设计下,我们就可以很容易的添加新的模型的转换,也可以轻而易举的将Spring事物管理集成进流程引擎。遵循了这个原则,流程引擎和spring的集成、和其他组件的集成也就顺理成章了。
 
4、依赖倒置原则
      该原则应该是OO最核心的原则,也是我们流程引擎完全遵循的原则。其大致概念为:一切依赖于抽象,一切面向接口变成,所有的细节全部依赖于抽象,不允许抽象依赖于具体实现,所有的客户端全部依赖于抽象耦合。FoxBPM流程引擎整体架构设计时全部遵循该原则,但具体功能模块实现时存在个别缺陷,并没有彻底的遵循该原则。依然存在:继承具体类的、变量指向具体类的引用、子类方法重写父类中已经实现的方法等等情况,其实某些相对稳定的很难再变化的模块存在这些情况也无可厚非。带有过程色彩的引擎架构,在该原则下同样富有弹性、可重用性、所有抽象和细节彼此隔离。
 
 
FoxBPM流程引擎都是怎么遵循这些原则的?都是通过哪些方式来遵循的?
好,守得云开见月明!带着这些疑问我们继续来看系统架构设计时所运用的一些设计模式。其实架构设计时设计模式很好的运用就是遵循OO原则的最好体现。比如说命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象,解耦的同时也体现了模块设计遵循单一职责原则;比如说装饰者设计模式,动态添加对象的功能,也体现了开闭原则;构建模式在将一个复杂的构建与其表示相分离的时候也体现了依赖倒置原则等等。
 
1、Command设计模式和责任链设计模式
印象最深的是Command设计模式,FoxBPM流程引擎的上层接口,每一个功都封装为一个命令然后交给一个责任链去处理,责任链处理过程包括:创建命令环境、设置流程引擎配置环境、启动事物、记录请求参数、执行命令、持久化缓存、清空表达式引擎环境、清空命令环境、清空流程引擎环境。
   相关代码模块如下所示:
  
 
    cmd定义模块如下图:
   
 
 CommandContextInterceptor负责命令执行之前环境初始化,LogInterceptor负责命令执行的日志记录,SpringTransactionInterceptor负责事物管理、CommandInvoker负责最终任务的执行。
 
2、观察者设计模式 
前段时间做了一个运行轨迹监听器,该功能负责监听记录流程运行过程中产生的轨迹包括任务节点进入、执行、离开,线条网关的执行。该模块相对独立,实现的也很容易,都是得益于该设计。流程运转中连接器的执行也是基于该设计模式。
   我们可以在虚拟机里面看节点容器类KernelFlowElementsContainerImpl里面包含了一个监听器的定义,目前监听的注册包括两个模块,一个是由BPMN模型转化到虚拟机模型时注册、一个是用户自己扩展的监听器注册。
    代码如以下所示:
public class KernelFlowElementsContainerImpl extends KernelFlowElementImpl
		implements
			KernelFlowElementsContainer { 
	protected List<KernelFlowNodeImpl> flowNodes = new ArrayList<KernelFlowNodeImpl>();
	protected Map<String, KernelFlowNodeImpl> namedFlowNodes = new HashMap<String, KernelFlowNodeImpl>();
	protected Map<String, KernelSequenceFlowImpl> sequenceFlows = new HashMap<String, KernelSequenceFlowImpl>();

	protected List<KernelLaneSet> laneSets = new ArrayList<KernelLaneSet>();
	protected List<KernelArtifact> artifacts = new ArrayList<KernelArtifact>();
	protected Map<String, List<KernelListener>> kernelListeners = new HashMap<String, List<KernelListener>>();
   
   相关事件执行代码如下:
public void execute(InterpretableExecutionContext executionContext) {
		KernelFlowElementsContainerImpl container = getContainer(executionContext);		
		String eventName = getEventName();
		List<KernelListener> kernelListeners = container.getKernelListeners(eventName);
		int kernelListenerIndex = executionContext.getKernelListenerIndex();
		if (kernelListeners.size() > kernelListenerIndex) {
			executionContext.setEventName(eventName);
			executionContext.setEventSource(container);
			KernelListener listener = kernelListeners.get(kernelListenerIndex);
			try {
				listener.notify(executionContext);
			} catch (RuntimeException e) {
				throw e;
			} catch (Exception e) {
				throw new KernelException("不能执行事件监听 : " + e.getMessage(), e);
			}
			executionContext.setKernelListenerIndex(kernelListenerIndex + 1);
			executionContext.fireEvent(this);

		} 
	}
   
基于监听器的设计,目前已经扩展的功能包括流程实例启动结束的监听、流程运行轨迹的监听、流程运转中连接器(包括邮件、数据库、WEB服务等等)的执行。
   虚拟机监听器扩展如下图所示:
    
 
3、组合设计模式
FoxBPM流程引擎虚拟机的流程定义结构、以及BPMN的EMF模型都是基于组合设计模式,在针对组合设计客户端可以很好的处理解析,比如说模型解析的转换,SVG转换。       
查看SVG构造模块我们可以发现,SVG构造工厂引用的是KernelBaseElement类而不是像kernelSequenceFlowImpl、kernelAssociationImpl、KernelFlowNodeImpl等这样具体子类,这样就可以屏蔽掉差异,保证客户端操作的一致
 
   SVG客户端代码:
public abstract class AbstractFlowElementVOFactory {   
	protected String voTemplateFileName;
	protected KernelBaseElement kernelBaseElement;
 
   KernelBaseElement类的定义如下所示:
public class KernelBaseElementImpl implements KernelBaseElement, KernelDIBounds { 
	private static final long serialVersionUID = 1L;

	protected String id;
	protected String name;
	protected KernelProcessDefinitionImpl processDefinition;
	protected Map<String, Object> properties;

	// 图形信息
	protected float x = -1;
	protected float y = -1;
	protected float width = -1;
	protected float height = -1;

	public KernelBaseElementImpl(String id, KernelProcessDefinitionImpl processDefinition) {
		this.id = id;
		this.processDefinition = processDefinition;
	}
 
   树形结构如下所示:
   
 
 4、模板方法设计模式
模板方法是代码复用的一项基本的技术,在类库中尤其重要。,它遵循“抽象类应当拥有尽可能多的行为,应当拥有尽可能少的数据”的重构原则,模板设计模式应该是所有设计模式中最基础的最重要的一种。虚拟机所定义的流程实例,只能在内存中维护其运行状态,但是真实情况是我们必须将流程实例状态持久化,FoxBPM虚拟机设计时采用模板方法支持流程实例状态的持久化功能,从而构造一台真正能维护流程实例状态的虚拟机。
查看代码我们可以发现很多以下这样的代码机构,这也是最简单的模板方法。
   如下所示:
       public KernelProcessInstanceImpl getProcessInstance() {
		ensureProcessInstanceInitialized();
		return processInstance;
	}

	/** 子类需要重写这个方法 */
	protected void ensureProcessInstanceInitialized() {
		// TODO Auto-generated method stub

	}
 
5、中间者设计模式
我们开发过程中有时会遇到这样的情况,就是某两个模块存在关联关系,但是这两个模块自己却又不能直接和独立的维护他们自己的关系、这个时候我们就可以采用中间者设计模式。大家还记得“西门庆和潘金莲走到一起的故事”吗。
流程引擎中也有相关设计,比如流程转换过程中节点行为和边界事件行为的关联关系。这里是通过一个内部类来实现的,如下代码所示:
public static class BehaviorRelationMemo {
		/** 临时存储MAP */
		private Map<String, ActivityBehavior> attachActivityMap = new HashMap<String, ActivityBehavior>();
		private Map<String, List<EventBehavior>> beAttachedActivityMap = new HashMap<String, List<EventBehavior>>();
		
		/**
		 * 
		 * attachActivityAndBoundaryEventBehaviorRelation(创建Activity
		 * 和BoundaryEventBehavior之间的关联关系) void
		 * 
		 * @exception
		 * @since 1.0.0
		 */
		public void attachActivityAndBoundaryEventBehaviorRelation() {
			Set<String> keySet = beAttachedActivityMap.keySet();
			for (String activityID : keySet) {
				if (attachActivityMap.containsKey(activityID)) {
					List<EventBehavior> list = beAttachedActivityMap.get(activityID);
					for (EventBehavior behavior : list) {
						attachActivityMap.get(activityID).getBoundaryEvents().add((BoundaryEventBehavior) behavior);
					}
					
				}
			}
			this.attachActivityMap.clear();
			this.beAttachedActivityMap.clear();
		}
 
流程引擎系统架构优秀的设计还有很多很多,丰富多彩的API也有很多很多。作为FoxBPM产品发布前的一个铺垫,本文只是蜻蜓点水般的揭秘了一些FoxBPM引擎构架设计所遵循的部分典型的OO原则,和典型的设计模式。如有不足之处还望大家里多多指教!
 
 
 
 

====================================================================
声明:本文首发iteye blog,转载请注明作者信息及原文地址,谢谢


作者信息:
马恩亮(elma@wisedu.com) 

=====================================================================

  • 大小: 4.1 KB
  • 大小: 148.6 KB
  • 大小: 154.2 KB
  • 大小: 8 KB
  • 大小: 10.8 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics