Fujaba Associations Specification
From FujabaWiki
| Table of contents |
Main
Some Basics on Associations
Associations present relationships between classes. Associations are labeled by an association name and may be bi-directional or uni-directional. A bi-directional association can be navigated in either direction, an uni-directional association can be navigated in one direction only. Associations have at least two association ends. Each end is represented by a role name to clarify the context that an object takes within the association. The role names are also used for implementation purposes. One of the key aspects of an association is the cardinality, which is also called multiplicity. The multiplicity of an association end specifies the number of possible instances of the class associated with a single instance of the other end. Additionally, an association may be qualified by an instance attribute or a free qualifier, whose values serve to partition the set of instances associated with an instance across an association.
Implementation
Summarizing, an association can be characterized by the following attributes.
- number of involved classes
- association name
- role names
- cardinality
- qualifier
Binary associations are implemented by a combination of attributes and access methods. The attributes describe the relationship and methods define and update this relationship. Thus, depending on the cardinality of each association end, various combinations are possible. The following table gives an overview of the most common combined association end types. They are implemented by different attributes and methods.
| Associationtype | Cardinality | Qualifier | Key Cardinality |
|---|---|---|---|
| "To One" | 1 | - | - |
| "To Many" | n | - | - |
| Attributed qualified "To One" | n | attribute | 1 |
| Attributed qualified "To Many" | n | attribute | n |
| Qualified "To One" | n | any | 1 |
| Qualified "To Many" | n | any | n |
Implementation Instructions for Associations
- Associations have to be documented by an association comment (see example below).
- All associations, a particular class is involved in, have to be documented before the class's declaration.
- All attributes implementing an association have to be documented.
- All access methods have to be implemented as described in this documentation. All changes to the standard implementation must be documented.
Example for an Association Comment
/** * <h2>Associations</h2> * * <pre> * cardLeft cardRight * LeftClass ------------------------------ RightClass * leftRole rightRole * </pre> */
Some Notes on Using Collections to Manage Associations
Associations with a singular multiplicity 'ToOne' are implemented as a simple attribute referencing the involved class object, and two methods (one getter and one setter) for manipulating that attribute. Implemention of all other associations is done by using one of the following collection classes and appropriated access methods.
- FHashSet
- FHashMap
- FDuplicatedHashMap
- FLinkedList
- FTreeSet
- FTreeMap
- FDuplicatedTreeMap
Using the appropriated access methods, collection classes enable you to keep track of zero or more items by adding and removing them from the collection as needed. One major difference between using a container based on hashing and a tree structure is the order during the iteration through the collection. Concerning the container based on hashing, the elements are returned by an iterator in the order of their insertion. In contrast, elements stored in a tree structure are returned by the iterator in sort order. Notice that elements stored in a container based on trees have to implement the Comparable interface. Although a standard comparator is available it is possible to define a more specific comparator.
"To One"-Association
/** * * <pre> * cardLeft 1 * LeftClass ------------------------------ RightClass * leftRole rightRole * </pre> */
| Atribute |
|---|
private RightClass rightrole; |
| Access Methods Summary | |
|---|---|
public boolean | setRightRole (RightClass value) |
public RightClass | getRightRole () |
| Access Methods |
|---|
public boolean setRightRole (RightClass value)
{
boolean changed = false;
if (this.rightRole != value)
{
if (this.rightRole != null)
{
RightClass oldValue = this.rightRole;
this.rightRole = null;
oldValue.<method to remove>;
}
this.rightRole = value;
if (value != null)
{
value.<method to insert>;
}
changed = true;
}
return changed;
}
|
public RightClass getRightRole ()
{
return this.rightRole;
}
|
| Comment |
|---|
Using a "To One" association in conjunction with a Qualified "To One" or "To Many" association would lead to the following signature:
public boolean setRightRole (KeyType key, RightClass value) <method to remove> = removeFromLeftRoles (key, this); <method to insert> = addToLeftRoles (key, this); |
"To Many" Association
/** * * <pre> * n * LeftClass -------------------------- RightClass * rightRoles * </pre> */
| Atribute |
|---|
private FHashSet rightRoles; or private FTreeSet rightRoles; or private FLinkedList rightRoles; |
Comment
public boolean addToRightRoles (KeyType key, RightClass value)
| Access Methods Summary | |
|---|---|
public boolean | hasInRightRoles (RightClass value) |
public Iterator | iteratorOfRightRoles () |
public int | sizeOfRightRoles () |
public boolean | addToRightRoles (RightClass value) |
public boolean | addToRightRoles (RightClass value) |
public boolean | removeFromRightRoles (RightClass value) |
public boolean | removeAllFromRightRoles () |
| Access Methods |
|---|
public boolean hasInRightRoles (RightClass value)
{
return ((this.rightRoles != null) &&
(value != null) &&
this.rightRoles.contains (value));
}
|
public Iterator iteratorOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.iterator ());
}
|
public int sizeOfRightRoles ()
{
return ((this.rightRoles == null)
? 0
: this.rightRoles.size ());
}
|
public boolean addToRightRoles (RightClass value)
{
boolean changed = false;
if (value != null [&& !hasInRightRoles (value)])
{
if (this.rightRoles == null)
{
this.rightRoles = new FHashSet ( $CONSTRUCTORPARAM$ ); // or FTreeSet () or FLinkedList ()
}
changed = this.rightRoles.add (value);
if (changed)
{
value.<method to insert>;
}
}
return changed;
}
|
public boolean removeFromRightRoles (RightClass value)
{
boolean changed = false;
if ((this.rightRoles != null) && (value != null))
{
changed = this.rightRoles.remove (value);
if (changed)
{
value.<method to remove>;
}
}
return changed;
}
|
public void removeAllFromRightRoles ()
{
RightClass tmpValue;
Iterator iter = this.iteratorOfRightRoles ();
while (iter.hasNext ())
{
tmpValue = (RightClass) iter.next ();
this.removeFromRightRoles (tmpValue);
}
}
|
| Comment |
|---|
Using a "To Many" association in conjunction with a Qualified "To One" or "To Many" association would lead to the following signatures:public boolean addToRightRoles (KeyType key, RightClass value) public boolean removeFromRightRoles (KeyType key, RightClass value) <method to remove> = removeFromLeftRoles (key, this); <method to insert> = addToLeftRoles (key, this); |
Attributed qualified "To One"-Association
/** * * <pre> * +----------+ 1 * LeftClass | getKey() +------------------- RightClass * +----------+ rightRoles * </pre> */
| Atribute |
|---|
private FHashMap rightRoles; or private FTreeMap rightRoles; |
| Access Methods Summary | |
|---|---|
public boolean | hasInRightRoles (RightClass value) |
public boolean | hasKeyInRightRoles (KeyType key) |
public Iterator | iteratorOfRightRoles () |
public Iterator | keysOfRightRoles () |
public Iterator | entriesOfRightRoles () |
public int | sizeOfRightRoles () |
public RightClass | getFromRightRoles (KeyType key) |
public boolean | addToRightRoles (RightClass value) |
public boolean | removeFromRightRoles (RightClass value) |
public boolean | removeKeyFromRightRoles (KeyType key) |
public void | removeAllFromRightRoles () |
| Access Methods |
|---|
public boolean hasInRightRoles (RightClass value)
{
return ((this.rightRoles != null) &&
(value != null) && (value.getKey () != null) &&
(this.rightRoles.get (value.getKey ()) == value));
}
|
public boolean hasKeyInRightRoles (KeyType key)
{
return ((this.rightRoles != null) &&
(key != null) &&
this.rightRoles.containsKey (key));
}
|
public Iterator iteratorOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.values ().iterator ());
}
|
public Iterator keysOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.keySet ().iterator ());
}
|
public Iterator entriesOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.entrySet ().iterator ());
}
|
public int sizeOfRightRoles ()
{
return ((this.rightRoles == null)
? 0
: this.rightRoles.size ());
}
|
public RightClass getFromRightRoles (KeyType key)
{
return (((this.rightRoles == null) || (key == null))
? null
: (RightClass) this.rightRoles.get (key));
}
|
public boolean addToRightRoles (RightClass value)
{
boolean changed = false;
if ((value != null) && (value.getKey () != null))
{
if (this.rightRoles == null)
{
this.rightRoles = new FHashSet ( $CONSTRUCTORPARAM$ ) ; // or FTreeMap ()
}
RightClass oldValue = (RightClass) this.rightRoles.put (value.getKey (), value);
if (oldValue != value)
{
if (oldValue != null)
{
oldValue.<method to remove>;
}
value.<method to insert>;
changed = true;
}
}
return changed;
}
|
public boolean removeFromRightRoles (RightClass value)
{
boolean changed = false;
if ((this.rightRoles != null) && (value != null) && (value.getKey () != null))
{
RightClass oldValue = (RightClass) this.rightRoles.get (value.getKey ());
if (oldValue == value)
{
this.rightRoles.remove (value.getKey ());
value.<method to remove>;
changed = true;
}
}
return changed;
}
|
public boolean removeKeyFromRightRoles (KeyType key)
{
boolean changed = false;
if ((this.rightRoles != null) && (key != null))
{
RightClass tmpValue = (RightClass) this.rightRoles.get (key);
if (tmpValue != null)
{
this.rightRoles.remove (key);
tmpValue.<method to remove>;
changed = true;
}
}
return changed;
}
|
public void removeAllFromRightRoles ()
{
RightClass tmpValue;
Iterator iter = this.iteratorOfRightRoles ();
while (iter.hasNext ())
{
tmpValue = (RightClass) iter.next ();
this.removeFromRightRoles (tmpValue);
}
}
|
Attributed qualified "To Many"-Association
/** * * <pre> * +----------+ n * LeftClass | getKey() +------------------- RightClass * +----------+ rightRoles * </pre> */
| Atribute |
|---|
private FDuplicatedHashMap rightRoles; or private FDuplicatedTreeMap rightRoles; |
| Access Methods Summary | |
|---|---|
public boolean | hasInRightRoles (RightClass value) |
public boolean | hasKeyInRightRoles (KeyType key) |
public Iterator | iteratorOfRightRoles () |
public Iterator | iteratorOfRightRoles (KeyType key) |
public Iterator | keysOfRightRoles () |
public Iterator | entriesOfRightRoles () |
public int | sizeOfRightRoles () |
public int | sizeOfRightRoles (KeyType key) |
public boolean | addToRightRoles (RightClass value) |
public boolean | removeFromRightRoles (RightClass value) |
public boolean | removeKeyFromRightRoles (KeyType key) |
public void | removeAllFromRightRoles () |
| Access Methods |
|---|
public boolean hasInRightRoles (RightClass value)
{
return ((this.rightRoles != null) &&
(value != null) && (value.getKey () != null) &&
this.rightRoles.containsEntry (value.getKey (), value));
}
|
public boolean hasKeyInRightRoles (KeyType key)
{
return ((this.rightRoles != null) &&
(key != null) &&
this.rightRoles.containsKey (key));
}
|
public Iterator iteratorOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.values ().iterator ());
}
|
public Iterator iteratorOfRightRoles (KeyType key)
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: FCollections.iterator (this.rightRoles.values (key)));
}
|
public Iterator keysOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.keySet ().iterator ());
}
|
public Iterator entriesOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.entrySet ().iterator ());
}
|
public int sizeOfRightRoles ()
{
return ((this.rightRoles == null)
? 0
: this.rightRoles.size ());
}
|
public int sizeOfRightRoles (KeyType key)
{
return ((this.rightRoles == null)
? 0
: this.rightRoles.size (key));
}
|
public boolean addToRightRoles (RightClass value)
{
boolean changed = false;
if ((value != null) && (value.getKey () != null))
{
if (this.rightRoles == null)
{
this.rightRoles = new FHashSet ( $CONSTRUCTORPARAM$ ) ; // or FDuplicatedTreeMap ()
}
RightClass oldValue = (RightClass) this.rightRoles.put (value.getKey (), value);
if (oldValue == null)
{
value.<method to insert>;
changed = true;
}
}
return changed;
}
|
public boolean removeFromRightRoles (RightClass value)
{
boolean changed = false;
if ((this.rightRoles != null) && (value != null) && (value.getKey () != null))
{
RightClass oldValue = (RightClass) this.rightRoles.remove (value.getKey (), value);
if (oldValue != null)
{
value.<method to remove>;
changed = true;
}
}
return changed;
}
|
public boolean removeKeyFromRightRoles (KeyType key)
{
boolean changed = false;
if ((this.rightRoles != null) && (key != null))
{
Collection tmpCol = (Collection) this.rightRoles.remove (key);
if (tmpCol != null)
{
RightClass tmpValue;
Iterator iter = tmpCol.iterator ();
while (iter.hasNext ())
{
tmpValue = (RightClass) iter.next ();
tmpValue.<method to remove>;
}
changed = true;
}
}
return changed;
}
|
public void removeAllFromRightRoles ()
{
RightClass tmpValue;
Iterator iter = this.iteratorOfRightRoles ();
while (iter.hasNext ())
{
tmpValue = (RightClass) iter.next ();
this.removeFromRightRoles (tmpValue);
}
}
|
Qualified "To One"-Association
/** * <pre> * +-----+ 1 * LeftClass | key +------------------- RightClass * +-----+ rightrole * </pre> */
| Atribute |
|---|
private FHashMap rightRoles; or private FTreeMap rightRoles; |
| Access Methods Summary | |
|---|---|
public boolean | hasInRightRoles (RightClass value) |
public boolean | hasInRightRoles (KeyType key, RightClass value) |
public boolean | hasKeyInRightRoles (KeyType key) |
public Iterator | iteratorOfRightRoles () |
public Iterator | keysOfRightRoles () |
public Iterator | entriesOfRightRoles () |
public int | sizeOfRightRoles () |
public RightClass | getFromRightRoles (KeyType key) |
public boolean | addToRightRoles (KeyType key, RightClass value) |
public boolean | addToRightRoles (Map.Entry entry) |
public boolean | removeFromRightRoles (RightClass value) |
public boolean | removeFromRightRoles (KeyType key, RightClass value) |
public boolean | removeKeyFromRightRoles (KeyType key) |
public void | removeAllFromRightRoles () |
| Access Methods |
|---|
public boolean hasInRightRoles (RightClass value)
{
return ((this.rightRoles != null) &&
(value != null) &&
this.rightRoles.containsValue (value));
}
|
public boolean hasInRightRoles (KeyType key, RightClass value)
{
return ((this.rightRoles != null) &&
(value != null) && (key != null) &&
(this.rightRoles.get (key) == value));
}
|
public boolean hasKeyInRightRoles (KeyType key)
{
return ((this.rightRoles != null) &&
(key != null) &&
this.rightRoles.containsKey (key));
}
|
public Iterator iteratorOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.values ().iterator ());
}
|
public Iterator keysOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.keySet ().iterator ());
}
|
public Iterator entriesOfRightRoles ()
{
return ((this.rightRoles == null)
? FEmptyIterator.get ()
: this.rightRoles.entrySet ().iterator ());
}
|
public int sizeOfRightRoles ()
{
return ((this.rightRoles == null)
? 0
: this.rightRoles.size ());
}
|
public RightClass getFromRightRoles (KeyType key)
{
return (((this.rightRoles == null) || (key == null))
? null
: (RightClass) this.rightRoles.get (key));
}
|
public boolean addToRightRoles (KeyType key, RightClass value)
{
boolean changed = false;
if ((value != null) && (key != null))
{
if (this.rightRoles == null)
{
this.rightRoles = new FHashSet ( $CONSTRUCTORPARAM$ ) ; // or FTreeMap
}
RightClass oldValue = (RightClass) this.rightRoles.put (key, value);
if (oldValue != value)
{
if (oldValue != null)
{
oldValue.<method to remove>;
}
value.<method to insert>;
changed = true;
}
}
return changed;
}
|
public boolean addToRightRoles (Map.Entry entry)
{
return addToRightRoles ((KeyType) entry.getKey (), (RightClass) entry.getValue ());
}
|
public boolean removeFromRightRoles (RightClass value)
{
boolean changed = false;
if ((this.rightRoles != null) && (value != null))
{
Iterator iter = this.entriesOfRightRoles ();
Map.Entry entry;
while (iter.hasNext ())
{
entry = (Map.Entry) iter.next ();
if (entry.getValue () == value)
{
changed = changed || this.removeFromRightRoles ((KeyType) entry.getKey (), value);
}
}
}
return changed;
}
|
public boolean removeFromRightRoles (KeyType key, RightClass value)
{
boolean changed = false;
if ((this.rightRoles != null) && (value != null) && (key != null))
{
RightClass oldValue = (RightClass) this.rightRoles.get (key);
if (oldValue == value)
{
this.rightRoles.remove (key);
value.<method to remove>;
changed = true;
}
}
return changed;
}
|
public boolean removeKeyFromRightRoles (KeyType key)
{
boolean changed = false;
if ((this.rightRoles != null) && (key != null))
{
RightClass tmpValue = (RightClass) this.rightRoles.get (key);
if (tmpValue != null)
{
this.rightRoles.remove (key);
tmpValue.<method to remove>;
changed = true;
}
}
return changed;
}
|
public void removeAllFromRightRoles ()
{
Iterator iter = entriesOfRightRoles ();
Map.Entry entry;
while (iter.hasNext ())
{
entry = (Map.Entry) iter.next ();
removeFromRightRoles ((KeyType) entry.getKey (), (RightClass) entry.getValue ());
}
}
|
Qualified "To Many"-Association
/** * * <pre> * +-----+ n * LeftClass | key +------------------- RightClass * +-----+ rightRoles * </pre> */
| Atribute |
|---|
private FDuplicatedHashMap rightRoles; or private FDuplicatedTreeMap rightRoles; |
| Access Methods Summary | |
|---|---|
public boolean | hasInRightRoles (RightClass value) |
public boolean | hasInRightRoles (KeyType key, RightClass value) |
public boolean | hasKeyInRightRoles (KeyType key) |
public Iterator | iteratorOfRightRoles () |
public Iterator | iteratorOfRightRoles (KeyType key) |
public Iterator | keysOfRightRoles () |
public Iterator | entriesOfRightRoles () |
public int | sizeOfRightRoles () |
public int | sizeOfRightRoles (KeyType key) |
public boolean | addToRightRoles (KeyType key, RightClass value) |
public boolean | addToRightRoles (Map.Entry entry) |
public boolean | removeFromRightRoles (RightClass value) |
public boolean | removeFromRightRoles (KeyType key, RightClass value) |
public boolean | removeKeyFromRightRoles (KeyType key) |
public void | removeAllFromRightRoles () |
| Access Methods |
|---|

