Saturday, June 30, 2007

Nodes and Links, decoupled

One constraint in this problem was to use the observer pattern, so that activation spreading is easy to implement, and new associations can be created during a run. (Though this is something that Good-Old-Farg, such as Copycat, Tabletop, or Metacat don't do, it should be built in, for learning). The other constraint was that the system should be decoupled. If class A uses class B, then class B cannot use class A in any way.

The first implementation of activation spreading had nodes as observers and nodes as observable subjects. Whenever a node was spreading activation it simply notified its registered observers. So, if you'd like to create additional functionality by bringing in a link class with different types of links, different distances, and so on, this class would depend on the node class. The node class, on the other hand, would also depend on the link class, such that whenever activation spreading took place, information from the link type, link distance, etc, should be brought in. That certainly wouldn't respect the Hollywood principle.

A better design is to decouple, by making the TLink (the link class) as the observer of TNode. So whenever Tnode notifies changes in activation, instead of other nodes receiving these messages, the links would receive them, and the links include a Tnode as a "destination" node. So now, to create a link, the main program has to create 2 nodes, create a link with the destination node, and register that link in the origin node. The design is decoupled, in the sense that any node can have changing associations being assigned and deleted during runtime. Moreover, to change node functionality, the class Tnode is changed (or subclassed), and to change link functionality, the other class changes with no regard to the implementation details of each other.

So here's what the new design looks like:

TActivationObserverClass = Class (TInterfacedObject, IObserverActivation)
{Observer Interface here}
procedure Update(Received_Activation: Tactivation); virtual;abstract;

Tnode = class (TInterfacedObject, ISubjectActivation)
associations: tlist;
previous_level: real;

activation: Tactivation;
constructor create;

{Observable (Subject) interface here}
procedure RegisterObserver(const Observer: TObject);
procedure UnRegisterObserver(const Observer: TObject);
procedure Notify (Sent_Activation: TActivation);

TLink = Class (TActivationObserverClass)

link_drag: real;
Dest_Node: TNode;

constructor create (destination: TNode; drag: real);

{Observer Interface here}
procedure Update(Received_Activation: Tactivation); override;