From Schmid.wiki
Jump to: navigation, search

Purpose

The Exclusively Active design pattern restricts active behaviour (the definition of which is different in different applications) to a single Exclusively Active instance.

When UpdateAll is called, the active instance has UpdateActive() invoked, and all other instances have UpdateInactive() invoked.

The only way to become active is to call Activate(), which 'steals' the active state from any currently active instance.

Design

class ExclusivelyActive {

public:

  ExclusivelyActive() -> if(instances == null)
                             instances = new List<ExclusivelyActive>
                         instances.Add(this)

  Activate()          -> if(Active != this)
                             if(Active != null)
                                 Active.Deactivate
                             Active = this
  
  Deactivate()        -> if(Active == this)
                             Active = null
  
  static UpdateAll()  -> for each ExclusivelyActive ea in instances
                             if(Active == ea) ea.updateActive
                             else ea.updateInactive

  Destroy()           -> if(Active != null)
                             Active.Deactivate
                         if(instances != null) instances.Remove(this)
  
  static ExclusivelyActive Active [get]

protected:

  updateActive()
  updateInactive()
  
  static List<ExclusivelyActive> instances
}

Polymorphic version - inherit classes from this to make only one instance of the derived classes active at a time:

abstract class ExclusivelyActiveBase {

public:

  ExclusivelyActiveBase() -> if(instances == null)
                                 instances = new List<ExclusivelyActiveBase>
			     instances.Add(this)

  Activate()          -> if(Active != this)
                             if(Active != null)
                                 Active.Deactivate
                             Active = this
			     activate()
  
  Deactivate()        -> if(Active == this)
                             Active = null
			     deactivate()
  
  static UpdateAll()  -> for each ExclusivelyActiveBase ea in instances
                             if(Active == ea) ea.updateActive
                             else ea.updateInactive

  Destroy()           -> if(Active != null)
                             Active.Deactivate
                         if(instances != null) instances.Remove(this)
  
  static ExclusivelyActiveBase Active [get]

protected:

  abstract updateActive()    │ all these must be implemented by
  abstract updateInactive()  │ the derived classes
  abstract activate()        │
  abstract deactivate()      │
  
  static List<ExclusivelyActiveBase> instances
}

Notes

  • At any time, there can be 0-1 active instances.
  • This design pattern is not thread safe.
  • This design pattern was designed by Jakob Schmid in the summer of 2009.

Example

/* This design ensures that only a single InputReceiver receives
 * input from the InputController class; thus, no instance is able
 * to 'steal' input from another without EnableInput being called.
 */
class InputReceiver {

    public static InputReceiver ActiveReceiver = null;
    static List<InputReceiver> instances;

    public InputReceiver() {
        if(instances == null) instances = new List<InputReceiver>();
        instances.Add(this);
    }

    // Activate
    public void EnableInput() {
        if(ActiveReceiver != this) {
	    if(ActiveReceiver != null) ActiveReceiver.DisableInput();
	    ActiveReceiver = this;
	}
    }

    // Deactivate
    public void DisableInput() {
        if(ActiveReceiver == this) ActiveReceiver = null;
    }

    /* The InputEvents are dequeued in the input controller which
     * calls this method. The InputEvents can be private and thus
     * access to them are locked to the active InputReceiver.
     */
    public static UpdateAll(List<InputEvent> inputEvents) {
        foreach(InputReceiver m in instances) {
            if(ActiveReceiver == m) m.updateActive(inputEvents);
            else m.updateInactive();
	}
    }

    // Active behaviour: get input
    protected void updateActive(List<InputEvent> inputEvents) {

        // do stuff with inputEvents
    }

    // Inactive behaviour: do nothing
    protected void updateInactive() { }
}

class InputController {

    // ...

    public void Update() {
        List<InputEvent> inputEvents = dequeueEvents();
        InputReceiver.UpdateAll(inputEvents);
    }
}