views:

424

answers:

4

I have a container that holds map of elements.

class MyContainer{
.....
Map<String,MyElement> elements = new ...
...
}

Each element has name property. The key in the map is the element's name. i.e. the method insert is as follows:

void addElement(MyElement elem){
    elements.put(elem.getName,elem);
 }

I need to use the map data structure, because I have many read operations based on the element name.

The problem is that I need to support modification of the element's name. Changing element name must derive changes in the map. (insert the element with a new key otherwise I won't be able to find that element)

I have thought about two options:

  1. add setName method to MyElement class that will update the container that its name was changed.

  2. don't add setName method to MyElement class, add rename element method to the container, the container will be in charge of updating both the element name and the key in the map.

Option 1 means I have to maintain reference from each element to the container. (this part of the program should maintain low memory footprint).

What do you say? do you see a better option?

+1  A: 

I would fire a property change notification on the setName method of the element and handle it in the container object which is listening that notification.

hakan
Note, this might be a good solution, but it will increase the size of the element: each event registration will mean the element will need to keep hold of a reference to the target function that handles the event.
Scott Langham
+1  A: 

First of all, note that if MyElement can conceivably be used in a context without MyContainer, then option 1 is out.

MyContainer has an obvious relation with MyElement, since its code references MyElement instances through its map. The reverse is not true: the code in MyElement does not need to reference MyContainer. So option 2 is better.

Perhaps, though, you could go for a third hybrid option:

  • MyElement has a rename method that only changes its own name, and MyContainer has a rename method which calls MyElement.rename and moves the object in the map to the new key.
Stephan202
A: 

If the element is only used in this container.

Put the rename operation on the container.

Make the rename method on the element private so another programmer can't accidentally change just the element and forget to update the container.

Scott Langham
A: 

Option 2 is the simplest and most efficient, thus my choice. Clearly you know that, so what's the dillema?

Another option is to make a MyString class, that will serve as both a std::string AND a reference to MyContainer. MyString's modifying methods would be in charge of re-maping, and you'd still have a low footprint. E.g.:

class MyString;
class MyElement {
...
   MyString name;
...
};

MyContainer * aContainer = new MyContainer;
new MyElement(MyString("Yaron Cohen",aContainer), ...); /* MyString need to be explicit only upon MyElement construction. takes care of inserting into container. */
...
MyElement * someElement = aContainer["Yaron Cohen"]; /* just std::string for lookup */
someElement->name = "Dana International": /* MyString takes care of remapping */

Note that this option supprts multiple keys and containers as well, e.g. FirstName, LastName (if only these were unique...)

Another option is if MyContainer is a singleton.

One more thing to consider is, how often does name change?