跟JBPM学设计模式之组合模式

JBPM学设计模式之组合模式

模式简介

        组合模式,将对象组合成树形结构以表示“部分与整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

        合成模式属于对象的结构模式,合成模式将对象组织到树形的结构中,可以用来描述整体与部分的关系。合成模式可以是客户端将单纯元素和复合元素同等的看待。

        树形结构在各种类型的语言中发挥了巨大的作用,一个基于集成类型的等级结构就是一个树结构;同样一个基于合成的对象的结构也是一个树结构。在编程中我们一般遇到的树结构都是连通的有方向的树形结构。

        有向树结构可以分为三种,从上到下、从下到上、双向的。这三种图中,树的节点和他们之间的关系都是一样的,但是连接他们的关系的方向却是不一样的。

        在由上到下的树图(如下图1-1)中,每一个树枝节点都有箭头指向它的所有子节点,从而客户可以要求每个树枝节点都给出自己所有的子节点,而一个节点却并不知道它的父节点。在这样的树结构中信息可以按照箭头自上向下传播。

跟JBPM学设计模式之组合模式

1-1

        在一个由下向上的树图(如下图1-2)中,每个节点的箭头都指向它的父节点,但是一个父节点却不知道其子节点。信息可以按照箭头所指的方向自下向上传播。

跟JBPM学设计模式之组合模式

1-2

        在一个双向的树图(如下图1-3)中,每一个节点都同时知道它的父节点和子节点。信息可以按照箭头的方向向两个方向传播。

跟JBPM学设计模式之组合模式

1-3

        一个树结构是由两种节点组成的,树枝节点和树叶节点。前者可以包括子节点,后者不能有子节点。所以可以说树枝节点是承载树叶节点的容器。

        组合模式的结构如下图1-4中所示,在图中我们可以看到其涉及到三个角色:

        抽象构件角色(Compnent):这是一个抽象角色,它给参加组合的对象规定共有的接口和默认行为。

        树叶构件角色(Leaf):代表参加组合的树叶对象,树叶对象没有子对象,规定了参加组合的原始对象的行为。

        树枝构件角色(Composite):代表参加组合的有子对象的对象,给出了树枝构件对象的行为.

跟JBPM学设计模式之组合模式

图 1-4

        合成模式可以不提供父对象的管理方法,但是必须提供诸如添加、删除、获取子对象的的管理方法;所以根据所实现的接口的是否提供相应的管理方法分为两种形式,分别称为安全式和透明式。虽然这是模式的实现问题,但是却影响到模式结构的细节。

        透明式组合模式(如下图1-5),在Component里声明所有用来管理子类对象的方法。这样所有的构件类都具有相同的接口。从接口层次看来,树枝对象和树叶对象是没有区别的,客户可以同等的对待所有的对象。但是其缺点就是不够安全,因为树叶节点是不可能有子对象的,因此其管理子对象的方法是没有意义的,但是编译时期不会出错,而只会在运行时期才会出错。

跟JBPM学设计模式之组合模式

1-5

        安全式组合模式(如下图1-6),在Composite里声明所有管理子类对象的方法。这样的做法是安全的做法,因为树叶节点本来根本就没有管理子类对象的方法,因此,如果对树叶对象使用这些方法,程序就会在编译器出错,而不是等到运行时才出错。

跟JBPM学设计模式之组合模式

1-6

JBPM中的组合模式

         JBPM中的活动节点模型具有透明组合模式的特征。我们知道JBPM中的节点有复合类型,也就是可以承载子节点;虽然从业务上来说,只有group类型的节点才能承载子节点,但是从JBPMActivityImpl的模型设计上来看,任何类型的节点都有ActivityImpl承载,自然任何类型的节点都可以承载子节点。具体的结构图如下1-7所示

跟JBPM学设计模式之组合模式

1-7

        抽象构件角色:这里由ActivityCompositeElement共同完成抽象构件角色。前者向客户提供节点相关的业务功能接口,后者提供树叶构件需要具有的管理子类对象的方法接口。

View Code
public  interface Activity {

   /**  the short display name given to this element.  */
  String getName();

   /**  the list of outgoing transitions.
   * Caution: the actual member is returned.  No copy is made. 
*/
  List<?  extends Transition> getOutgoingTransitions();

   /**  the default outgoing transition.  */
  Transition getDefaultOutgoingTransition();

   /**  the first leaving transition with the given name or null of no
   * such leaving transition exists. If the multiple transitions have 
   * the given transition name, the first (in order of {
@link  #getOutgoingTransitions()})
   * will be returned.
   *  
   * 
@param  transitionName is the name of the transition to take.  A null value will 
   * match the first unnamed transition. 
*/
  Transition getOutgoingTransition(String transitionName);

   /**  indicates if a leaving transition with the given transitionName exists. 
   * A null value matches an unnamed transition. 
*/
   boolean hasOutgoingTransition(String transitionName);

   /**  indicates if this activity has leaving transitions  */
   boolean hasOutgoingTransitions();

   /**  the leaving transitions, keyed by transition name.  If a transition with 
   * the same name occurs mutltiple times, the first one is returned.
   * Leaving transitions with a null value for their name are not included 
   * in the map.
   * Beware: the actual member is returned.  No copy is made.  In fact, the 
   * returned map is maintained as a cache.  So updates to the map will 
   * influence subsequent retrievals of outgoing transitions by name. 
*/
  Map<String, ?  extends Transition> getOutgoingTransitionsMap();
  
   /**  searches for the given transitionName in this activity and then up the 
   * parent chain. Returns null if no such transition is found. 
*/
  Transition findOutgoingTransition(String transitionName);

   /**  the list of arriving transitions.
   * Beware: the actual member is returned.  No copy is made. 
*/
  List<?  extends Transition> getIncomingTransitions();

   /**  indicates if this activity has arriving transitions  */
   boolean hasIncomingTransitions();
  
   /**  retrieve the parent activity in the composite activity structure.  This is 
   * different from {
@link  ObservableElement#getParent()} in that it is restricted 
   * to the parent activities.  It doesn't take into account the process definition. 
*/ 
  Activity getParentActivity();
  
   /**  indicates if this processDefinition has activities.  */
   boolean hasActivities();

   /**  the list of direct composite activities.  Recursively contained 
   * activities are not included in the list. 
   * Beware: the actual member is returned.  No copy is made. 
*/
  List<?  extends Activity> getActivities();

   /**  indicates if an activity with the given name exists directly in 
   * this element.  Only the direct contained activities are 
   * searched.  No recursive search is made. 
*/
   boolean hasActivity(String activityName);

   /**  the first composite activity with the given name or null of no
   * such activity exists. Only the direct contained activities are 
   * searched.  No recursive search is made. 
*/
  Activity getActivity(String activityName);

   /**  searches for the given activity in this element recursively, 
   * including this activity and all child activities.  The search 
   * is done depth-first. A null value for activityName matches a activity 
   * without a name. 
*/
  Activity findActivity(String activityName);

   /**  the composite activities, keyed by activity name.  If an activity 
   * with the same name occurs mutltiple times, the first in the list
   * is included in the map. Activities with a null value for their name 
   * are not included in the map. 
   * Beware: the actual member is returned.  No copy is made. In fact, the 
   * returned map is maintained as a cache.  So updates to the map will 
   * influence subsequent retrievals of activities by name.
*/
  Map<String, ?  extends Activity> getActivitiesMap();

   /**  the type of this activity which corresponds to the xml tag  */
  String getType();
}

 

View Code
public  interface CompositeElement  extends ObservableElement {

   /**  indicates if this processDefinition has activities.  */
   boolean hasActivities();

   /**  the list of direct composite activities.  Recursively contained 
   * activities are not included in the list. 
   * Beware: the actual member is returned.  No copy is made. 
*/
  List<?  extends Activity> getActivities();

   /**  indicates if an activity with the given name exists directly in 
   * this element.  Only the direct contained activities are 
   * searched.  No recursive search is made. 
*/
   boolean hasActivity(String activityName);

   /**  the first composite activity with the given name or null of no
   * such activity exists. Only the direct contained activities are 
   * searched.  No recursive search is made. 
*/
  Activity getActivity(String activityName);

   /**  searches for the given activity in this element recursively, 
   * including this activity and all child activities.  The search 
   * is done depth-first. A null value for activityName matches a activity 
   * without a name. 
*/
  Activity findActivity(String activityName);

   /**  the composite activities, keyed by activity name.  If an activity 
   * with the same name occurs mutltiple times, the first in the list
   * is included in the map. Activities with a null value for their name 
   * are not included in the map. 
   * Beware: the actual member is returned.  No copy is made. In fact, the 
   * returned map is maintained as a cache.  So updates to the map will 
   * influence subsequent retrievals of activities by name.
*/
  Map<String, ?  extends Activity> getActivitiesMap();
}

        树枝构件角色:树枝构件由CompositeElementImpl担当,其具体实现对节点的管理功能。同时ActivityImpl直接继承CompositeElementImpl,所以它也是树枝构件。

View Code
public  abstract  class CompositeElementImpl  extends ScopeElementImpl  implements CompositeElement {

   private  static  final  long serialVersionUID = 1L;
  
   protected List<ActivityImpl> activities;
   transient  protected Map<String, ActivityImpl> activitiesMap;

   //  nested activities  //////////////////////////////////////////////////////////// /
  
   /**
   * creates a nested activity. Also the nested activity's parent pointer will be set 
   * appropriatly. 
   
*/
   public ActivityImpl createActivity() {
     return createActivity( null);
  }

   /**
   * creates a nested activity with the given name. Also the nested activity's parent pointer will be set 
   * appropriatly. 
   * 
@param  activityName may be null. 
   
*/
   public ActivityImpl createActivity(String activityName) {
    ActivityImpl activity =  new ActivityImpl();
    activity.setName(activityName);
    addActivity(activity);
     return activity;
  }

   public Activity addActivity(ActivityImpl activity) {
    activity.setProcessDefinition(processDefinition);
     if (activities== null) {
      activities =  new ArrayList<ActivityImpl>();
    }
     if (! activities.contains(activity)) {
      activities.add(activity);
    }
    activitiesMap =  null;
     return activity;
  }
  
   /**  removes the given activity from the nested activities.
   * Also the activity's parent will be nulled.
   * This method will do nothing if the activity is null or if 
   * the activity is not in the list of nested activities.
   * If the activity is actually removed from the list of 
   * activities, the activity's source will be nulled. 
   * In case this is the activity that was in the 
   * activitiesMap and another activity exists with the same
   * name, that activity (the first) will be put in the 
   * activitiesMap as a replacement for the removed activity.
   
*/
   public  boolean removeActivity(ActivityImpl activity) {
     if ( (activity!= null)
         && (activities!= null)
       ) {
       boolean isRemoved = activities.remove(activity);
       if (isRemoved) {
        activity.setParentActivity( null);
         if (activities.isEmpty()) {
          activities =  null;
        }
        activitiesMap =  null;
      }
       return isRemoved;
    }
     return  false;
  }

   /**  the first nested activity with the given name or null of no
   * such activity exists.
   
*/
   public ActivityImpl getActivity(String activityName) {
     return (getActivitiesMap()!= null ? activitiesMap.get(activityName) :  null);
  }

   /**  is this activity present ?  */
   public  boolean hasActivity(String activityName) {
     return ((getActivitiesMap()!= null) && (activitiesMap.containsKey(activityName)));
  }

   public ActivityImpl findActivity(String activityName) {
     if (activities!= null) {
       for(ActivityImpl n : activities) {
        ActivityImpl activity = n.findActivity(activityName);
         if (activity!= null) {
           return activity;
        }
      }
    }
     return  null;
  }

   /**  the list of nested activities.
   * Beware: the actual member is returned.  No copy is made. 
   
*/
   public List<?  extends Activity> getActivities() {
     return activities;
  }

   /**  the nested activities, keyed by activity name.  If a activity with 
   * the same name occurs mutltiple times, the first in the list
   * is included in the map.
   * Activities with a null value for their name are not included 
   * in the map.
   * Beware: the actual member is returned.  No copy is made. 
   
*/
   public Map<String, ?  extends Activity> getActivitiesMap() {
     if (activitiesMap ==  null) {
       this.activitiesMap = ActivityImpl.getActivitiesMap(activities);
    }
     return activitiesMap;
  }
  
   /**  indicates if this processDefinition has activities.  */
   public  boolean hasActivities() {
     return ((activities!= null) && (!activities.isEmpty()));
  }

}

        树叶构件角色:树叶构件角色由ActivityImpl来担当,ActivityImpl在没有子节点的时候,就是真正的树叶构件了。       

View Code
public  class ActivityImpl  extends CompositeElementImpl  implements Activity {

   private  static  final  long serialVersionUID = 1L;
  
   protected ActivityBehaviour activityBehaviour;
   protected  boolean isActivityBehaviourStateful =  false;
   protected Descriptor activityBehaviourDescriptor;
  
   protected List<TransitionImpl> outgoingTransitions =  new ArrayList<TransitionImpl>();
   protected List<TransitionImpl> incomingTransitions =  new ArrayList<TransitionImpl>();
   protected TransitionImpl defaultOutgoingTransition;
   protected ActivityImpl parentActivity;

   protected String type;
   protected Continuation continuation = Continuation.SYNCHRONOUS;

   protected ActivityCoordinatesImpl coordinates;
  
   //  Do not initialize. Caching is based on the nullity of this map
   transient  protected Map<String, TransitionImpl> outgoingTransitionsMap =  null;
  
   /**
   * Use {
@link  ProcessDefinitionImpl#createActivity()} or { @link  ActivityImpl#createActivity()} instead.
   
*/
   public ActivityImpl() {
     super();
  }
  
   //  specialized activity containment methods  //////////////////////////////////// /
  
   public ActivityImpl addActivity(ActivityImpl activity) {
    activity.setParentActivity( this);
     super.addActivity(activity);
     return activity;
  }
  
   public ActivityImpl findActivity(String activityName) {
     if (activityName== null) {
       if (name== null) {
         return  this;
      }
    }  else  if (activityName.equals(name)) {
       return  this;
    }
     return  super.findActivity(activityName);
  }

   //  outgoing transitions  //////////////////////////////////////////////////////

   /**  creates an outgoing transition from this activity.  */
   public TransitionImpl createOutgoingTransition() {
     //  create a new transition
    TransitionImpl transition =  new TransitionImpl();
    transition.setProcessDefinition(processDefinition);
    
     //  wire it between the source and destination
    addOutgoingTransition(transition);

     //  if there is no default transition yet
     if (defaultOutgoingTransition== null) {
       //  make this the default outgoing transition
      defaultOutgoingTransition = transition;
    }
    
     return transition;
  }
  
   /**
   * adds the given transition as a leaving transition to this activity.
   * Also the source of the transition is set to this activity.
   * Adding a transition that is already contained in the leaving 
   * transitions has no effect. 
   * 
@return  the added transition. 
   * 
@throws  NullPointerException if transition is null.
   
*/
   public Transition addOutgoingTransition(TransitionImpl transition) {
     if (! outgoingTransitions.contains(transition)) {
      transition.setSource( this);
      transition.setSourceIndex(outgoingTransitions.size());
      outgoingTransitions.add(transition);
      clearOutgoingTransitionsMap();
    }
     return transition;
  }

   /**
   * removes the given transition from the leaving transitions.
   * Also the transition's source will be nulled.
   * This method will do nothing if the transition is null or if 
   * the given transition is not in the list of this activity's leaving 
   * transitions.
   * In case this is the transition that was in the 
   * outgoingTransitionsMap and another transition exists with the same
   * name, that transition (the first) will be put in the 
   * outgoingTransitionsMap as a replacement for the removed transition.
   * If the transition is actually removed from the list of 
   * leaving transitions, the transition's source will be nulled. 
   
*/
   public  boolean removeOutgoingTransition(TransitionImpl transition) {
     if (transition!= null) {
       boolean isRemoved = outgoingTransitions.remove(transition);
       if (isRemoved) {
        transition.setSource( null);
        clearOutgoingTransitionsMap();
      }
       return isRemoved;
    }
     return  false;
  }

   /**  the first leaving transition with the given name or null of no
   * such leaving transition exists.
   
*/
   public TransitionImpl getOutgoingTransition(String transitionName) {
     return (getOutgoingTransitionsMap()!= null ? outgoingTransitionsMap.get(transitionName) :  null);
  }
  
   /**  searches for the given transitionName in this activity and then up the 
   * parent chain. Returns null if no such transition is found. 
*/
   public TransitionImpl findOutgoingTransition(String transitionName) {
    TransitionImpl transition = getOutgoingTransition(transitionName);
     if (transition!= null) {
       return transition;
    }
     if (parentActivity!= null) {
       return parentActivity.findOutgoingTransition(transitionName);
    }
     return  null;
  }
  
   /**  searches for the default transition in this activity and then up the 
   * parent chain. Returns null if no such transition is found. 
*/
   public TransitionImpl findDefaultTransition() {
     if (defaultOutgoingTransition!= null) {
       return defaultOutgoingTransition;
    }
     if (parentActivity!= null) {
       return parentActivity.findDefaultTransition();
    }
     return  null;
  }

  
   /**  the list of leaving transitions.
   * Beware: the actual member is returned.  No copy is made. 
   
*/
   public List<?  extends Transition> getOutgoingTransitions() {
     return outgoingTransitions;
  }

   /**  indicates if a leaving transition with the given transitionName exists.  */
   public  boolean hasOutgoingTransition(String transitionName) {
     return (getOutgoingTransition(transitionName)!= null);
  }

   /**  indicates if this activity has leaving transitions  */
   public  boolean hasOutgoingTransitions() {
     return !outgoingTransitions.isEmpty();
  }

   /**  sets the outgoingTransitions to the given list of outgoingTransitions.
   * A copy of the collection is made.  Also the outgoingTransitionsMap will 
   * be updated and the source of all the transitions in the given list will 
   * be set to this activity.
   * In case there was a leaving transitions list present, these transition's
   * source will be nulled.
   
*/
   public  void setOutgoingTransitions(List<TransitionImpl> outgoingTransitions) {
     if (! this.outgoingTransitions.isEmpty()) {
      List<TransitionImpl> removedTransitions =  new ArrayList<TransitionImpl>(outgoingTransitions);
       for (TransitionImpl removedTransition: removedTransitions) {
        removeOutgoingTransition(removedTransition);
      }
    }
     if (outgoingTransitions!= null) {
       this.outgoingTransitions =  new ArrayList<TransitionImpl>();
       for (TransitionImpl addedTransition: outgoingTransitions) {
        addOutgoingTransition(addedTransition);
      }
    }  else {
       this.outgoingTransitions =  new ArrayList<TransitionImpl>();
    }
    clearOutgoingTransitionsMap();
  }

   //  arriving transitions  //////////////////////////////////////////////////// /
  
   /**
   * adds the given transition as an arriving transition to this activity.
   * Also the source of the transition is set to this activity. 
   * 
@return  the added transition. 
   * 
@throws  NullPointerException if transition is null.
   
*/
   public Transition addIncomingTransition(TransitionImpl transition) {
    transition.setDestination( this);
    incomingTransitions.add(transition);
     return transition;
  }

   /**  removes the given transition if it is contained in the arriving
   * transitions of this activity.  If this transition was actually removed,
   * its destination pointer is nulled.
   * 
@return  true if a transition was removed.
   
*/
   public  boolean removeIncomingTransition(TransitionImpl transition) {
     if ( (transition!= null) && (incomingTransitions.remove(transition))) {
      transition.setDestination( null);
       return  true;
    }
     return  false;
  }

   /**  the list of arriving transitions.
   * Beware: the actual member is returned.  No copy is made.
   
*/ 
   public List<?  extends Transition> getIncomingTransitions() {
     return incomingTransitions;
  }

   /**  indicates if this activity has arriving transitions  */
   public  boolean hasIncomingTransitions() {
     return !incomingTransitions.isEmpty();
  }


   /**  sets the incomingTransitions to the given list of incomingTransitions.
   * A copy of the collection is made.  Also the destination of all the transitions 
   * in the given list will be set to this activity.
   * In case there was an arriving transitions list present, these transition's
   * destination will be nulled.
   
*/
   public  void setIncomingTransitions(List<TransitionImpl> incomingTransitions) {
     if (! this.incomingTransitions.isEmpty()) {
       for (TransitionImpl removedTransition:  this.incomingTransitions) {
        removedTransition.setDestination( null);
      }
    }
     if (incomingTransitions!= null) {
       this.incomingTransitions =  new ArrayList<TransitionImpl>(incomingTransitions);
       for (TransitionImpl addedTransition: incomingTransitions) {
        addedTransition.setDestination( this);
      }
    }  else {
       this.incomingTransitions =  null;
    }
  }

   /**  the leaving transitions, keyed by transition name.  If a transition with 
   * the same name occurs mutltiple times, the first one is returned.
   * Leaving transitions with a null value for their name are not included 
   * in the map.
   * Beware: the actual member is returned.  No copy is made. 
   
*/
   public Map<String, ?  extends Transition> getOutgoingTransitionsMap() {
     if(outgoingTransitionsMap ==  null){
      outgoingTransitionsMap =  new HashMap<String, TransitionImpl>();
       for (TransitionImpl transition: outgoingTransitions) {
         if (!outgoingTransitionsMap.containsKey(transition.getName())) {
          outgoingTransitionsMap.put(transition.getName(), transition);
        }
      }
    }
     return outgoingTransitionsMap;
  }

   void clearOutgoingTransitionsMap() {
    outgoingTransitionsMap =  null;
  }

   //  various helper methods  ////////////////////////////////////////////////// /
  

   static Map<String, ActivityImpl> getActivitiesMap(List<ActivityImpl> activities) {
    Map<String, ActivityImpl> map =  null;
     if (activities!= null) {
      map =  new HashMap<String, ActivityImpl>();
       for (ActivityImpl activity: activities) {
         if (! map.containsKey(activity.getName())) {
          map.put(activity.getName(), activity);
        }
      }
    }
     return map;
  }

   public String toString() { 
     if (name!= nullreturn "activity("+name+")";
     if (dbid!=0)  return "activity("+dbid+")";
     return "activity("+System.identityHashCode( this)+")"; 
  }

   /**  collects the full stack of parent in a list.  This activity is the 
   * first element in the chain.  The process definition will be the last element.
   * the chain will never be null. 
*/
   public List<ObservableElementImpl> getParentChain() {
    List<ObservableElementImpl> chain =  new ArrayList<ObservableElementImpl>();
    ObservableElementImpl processElement =  this;
     while (processElement!= null) {
      chain.add(processElement);
      processElement = processElement.getParent();
    }
     return chain;
  }

   public  boolean isAsync() {
     return ! (continuation==Continuation.SYNCHRONOUS);
  }

   public  boolean contains(ActivityImpl activity) {
     while (activity!= null) {
       if (activity.getParent()== this) {
         return  true;
      }
      activity = activity.getParentActivity();
    }
     return  false;
  }

   //  customized getters and setters  ////////////////////////////////////////// /

   public ActivityBehaviour getActivityBehaviour() {
     if (activityBehaviour!= null) {
       return activityBehaviour;
    }
     if (activityBehaviourDescriptor!= null) {
      ActivityBehaviour createdBehaviour = (ActivityBehaviour) ReflectUtil.instantiateUserCode(activityBehaviourDescriptor, processDefinition,  null);
       if (!isActivityBehaviourStateful) {
        activityBehaviour = createdBehaviour;
      }
       return createdBehaviour;
    }
     return  null;
  }

   //  getters and setters  //////////////////////////////////////////////////////
  
   public ObservableElementImpl getParent() {
     return (parentActivity!= null ? parentActivity : processDefinition);
  }
  
   public String getName() {
     return name;
  }
   public  void setName(String name) {
     this.name = name;
  }
   public TransitionImpl getDefaultOutgoingTransition() {
     return defaultOutgoingTransition;
  }
   public  void setDefaultOutgoingTransition(TransitionImpl defaultOutgoingTransition) {
     this.defaultOutgoingTransition = defaultOutgoingTransition;
  }
   public ActivityImpl getParentActivity() {
     return parentActivity;
  }
   public  void setParentActivity(ActivityImpl parentActivity) {
     this.parentActivity = parentActivity;
  }
   public String getType() {
     return type;
  }
   public  void setType(String type) {
     this.type = type;
  }
   public ActivityCoordinatesImpl getCoordinates() {
     return coordinates;
  }
   public  void setCoordinates(ActivityCoordinatesImpl coordinates) {
     this.coordinates = coordinates;
  }
   public Continuation getContinuation() {
     return continuation;
  }
   public  void setContinuation(Continuation continuation) {
     this.continuation = continuation;
  }
   public  void setActivityBehaviour(ActivityBehaviour activityBehaviour) {
     this.activityBehaviour = activityBehaviour;
  }
   public Descriptor getActivityBehaviourDescriptor() {
     return activityBehaviourDescriptor;
  }
   public  void setActivityBehaviourDescriptor(Descriptor activityBehaviourDescriptor) {
     this.activityBehaviourDescriptor = activityBehaviourDescriptor;
  }
   public  boolean isActivityBehaviourStateful() {
     return isActivityBehaviourStateful;
  }
   public  void setActivityBehaviourStateful( boolean isActivityBehaviourStateful) {
     this.isActivityBehaviourStateful = isActivityBehaviourStateful;
  }
}

         这里JBPM并没有严格按照模式的定义进行实现,而是根据业务进行了模型的分离。由于对子节点的管理是由流程引擎内部进行管理的,是不允许客户进行更改的;只需要向客户开放节点相关的业务接口;所以进行这样的实现还是符合业务实际场景的。

         JBPM中的对多历史数据库支持的session模型具有安全组合模式的特征的。具体的结构如下图(1-8)所示

跟JBPM学设计模式之组合模式

1-8

        抽象构件角色:这里由HistorySession担当,其提供启动记录历史信息的接口。每个该类的实例都会对应一个独立的数据库。

View Code
public  interface HistorySession {
  
   void process(HistoryEvent historyEvent);
  
}

       树叶构件角色:这里由HistorySessionImpl担当,其提供启动记录历史信息的具体实现。

       

View Code
public  class HistorySessionImpl  implements HistorySession {

   public  void process(HistoryEvent historyEvent) {
    historyEvent.process();
  }
}

        树枝构件角色:这里由HistorySessionChain担当,其作为承载子对象的容器,可以承载代表不同历史库的HistorySession的对象。

 

View Code
public  class HistorySessionChain  implements HistorySession {

   protected List<HistorySession> historySessions =  new ArrayList<HistorySession>();

   public HistorySessionChain(List<HistorySession> historySessions) {
     this.historySessions = historySessions;
  }

   public  void process(HistoryEvent historyEvent) {
     for (HistorySession historySession: historySessions) {
      historySession.process(historyEvent);
    }
  }
}

 

你可能感兴趣的:(设计模式)