views:

188

answers:

3

I have a class A maintaining a list of objects class B. But each object of class B can be referenced in any object of class A. Class B also maintains a list of objects of class A where it is being referenced. The program can and will create (several) objects of both class A and B 'at will' and also delete them.

If I use C# I can add and delete objects from both classes with following code

public class A
{
    private List<B>ListOfObjects_B;
    public bool Add(B Object)
    {
       bool bAdd = false;
       if ((Object != null) && (ListOfObjects_B.IndexOf(B) <0))
       {
          ListOfObjects_B.Add(Object);
          Object.Add(this);
          bAdded = true;
       }
       return bAdded;
    }

    public bool Delete(B Object)
    {
       bool bDeleted = ListOfObjects_B.Remove(Object);
       if (bDeleted == true) Object.Delete(this);
       return bDeleted;
    }
}

public class B
{
    private List<A>ListOfObjects_A;
    public bool Add(A Object)
    {
        bool bAdd = false;
        if ((Object != null) && (ListOfObjects_A.IndexOf(A) <0))
        {
            ListOfObjects_A.Add(Object);
            Object.Add(this);
            bAdded = true;
        }
        return bAdded;
   }

   public bool Delete(A Object)
   {
       bool bDeleted = ListOfObjects_A.Remove(Object);
       if (bDeleted == true) Object.Delete(this);
       return bDeleted;
   }
}

This will work as because of removing/adding the object to the ListOfObjects the SECOND time (by recursion) the function will be called it will fail to delete/add thereby avoiding an infinite loop.

But I don't like this code even though A and B do not know 'much' about the other class and just call a Delete/Add function.

I suppose this kind of problem is general and a design pattern exists for handling it in such a way that recursion can be avoided and updating both lists will be 'just better'. What design pattern should I use? I would appreciate if some code would be added as well.

+3  A: 

You can simplify thing by moving the "object association concern" into a dedicated class. Here's what I have in mind.

Define a class called AssociationTable. This class will maintain a list of pairs where each pair holds a reference to an A object and a reference to a B object.

Each A object (and each B object) will hold a reference to the AssociationTable object. A.Add(B) will be implemented as table.add(this, b); B.Add(A) will be implemented as table.add(a, this);

Deletion will be implemented as table.delete(this, b) or table.delete(a, this)

class Pair { 
  A a; B b; 
  Pair(A a, B b) { this.a = a; this.b = b; } 
  // Also override Equals(), HashCode()
}

class AssociationTalbe {
  Set<Pair> pairs = ...;

  void add(A a, B b) { pairs.add(new Pair(a, b)); }
  void remove(A a, B b) { pairs.remove(new Pair(a, b)); }
}

class A {
  AssociationTable table;

  public A(AssociationTable t) { table = t; }

  void add(B b) { table.add(this, b); }
  void remove(B b) { table.remove(this, b); }
}

Edit: The problem with this design is garbage collection. the table will hold references to objects thereby supressing their collection. In Java you could use a WeakReference object to overcome this issue. I am pretty sure there's something similar in the .Net world

Also, the table could be a singleton. I don't like singletons too much. In here, a singleton will make the A-B association unique across your program. This may be something that is undesirable but it depends on your concrete needs.

Finally, (just to put things in context) this design works the same way as Many-to-Many relationships in relational data bases.

Itay
That's also what I was thinking... +1
bruno conde
As such the idea seems good to me (thanks). But in my porgram I have several 'combinations' having this relationship. So I would like to have a solution using a template. so the "A" and "B" in class Pair would not be fixed but could also become "C" and "D" or maybe "E" and "A" .A singleton could be useful in my program as each A may only be linked to a B just once.
SoftwareTester
+1  A: 

About the only thing I can think of is using a Mediator pattern so that A doesn't add itself to B. Here's an example:

public class Mediator {

    public void Add(A List, B Object) {
        if(list.Add(Object)) {
            object.Add(List);
        }
    }

    public void Delete(A List, B Object) {
        if(List.Delete(Object)) {
            Object.Delete(List);
        }
    }
}

After this you would remove the lines of code which read "Object.Add(this);" and "if (bDeleted == true) Object.Delete(this);" This also has the benefit of reducing how many times each method is called as before object A's methods were being called twice since object B was also calling those methods on object A.

EDIT: Upon further review, I realized you were already using an Observer design pattern in a way. Object A is the observer and object B is the observable. Object A maintains a list of objects its observing and object B maintains a list of objects observing it. The only thing is I don't see any additional functionality, although there probably is some. Basically, Object B will notify all Object A's observing it that it's changed and all of those Object A's will ask for the change. If this is what you're looking for, then all you need to do is remove the lines "Object.Add(this);" and "if(bDeleted == true) Object.Delete(this);" from the B code as it is unnecessary.

indyK1ng
Obviously there is more functionality in the classes A and B.It is possible the user will invoke deletion of an object A, but also deletion of an object B can be invoked (separately) by the user. So whatever object will be deleted it needs to inform the other in order for the other to update its list. You're right A maintains a list of objects it is observing and B maintains a list of objects it's being observed by. But I don't see WHY I can remove "Object.Add(this)" as this line actually creates the reference
SoftwareTester
I was assuming that A was being told to add object B from an outside source. If it's being told to add object B via object B, then you might want to remove that line from Object A's source code. If can can be done from either, then you should probably make two different functions, one called from the other Object and one called from a different object to avoid the extra call being made.
indyK1ng
Also, I'm referring specifically to within B's Add function when I say remove Object.Add(this) since, if it's only being called from A, it just causes A's Add function to be called again. A already has a reference to B and B has a reference to A in the List of A objects.
indyK1ng
"If can can be done from either, then you should probably make two different functions, one called from the other Object and one called from a different object to avoid the extra call being made"<BR>How can I make to be callable by just ONE class? (Maybe my knowledge of C# isn't good enough, I just don't know)
SoftwareTester
You wouldn't make it callable from one class, you would make another method and only call that from one class. I don't think any languages allow you to specify what class can call a method. It would just be practice to use one method from the other class and one method from any class not mentioned here.
indyK1ng
+1  A: 

I recently wrote a class to handle a similar problem. It is actually a simpler scenario (parent/child relationship with the children referencing their parent), but you could probably adapt it for your needs. The main difference is that the Parent property in my implementation should be replaced by a collection of parents.

Thomas Levesque
Very interesting article, I will try it. Would you pls provide the code you omitted as well (maybe at the end of the article or [the whole code] in a file to be downloaded) as it would complete the implementation.
SoftwareTester
All the code you need is in the article... You just need to copy/paste the IChildItem interface and the ChildItemCollection class
Thomas Levesque