Dear ruby-ists,


I hope you will indulge this slightly (I hope) off-topic design question
since it is not specific to ruby design.


_Setting:_

Suppose you want to code an addressbook editor. You want it to be based
on *Addressbook* class that can be reused, so that other people may
write their UI on your addressbook format. How do you go about this ? 

My suggestion would be: create a *Contact* class that contains one persons
information (name, address, phone, ...). Then create a container for
*Contact* instances and call it *Addressbook*.

I imagine you would want the addressbook to be responsible for the way
it loads, stores and saves its contacts and hide the implementation
details from the world. One could write an interface like:

class Addressbook
  def Addressbook.open(file) {...}     (takes a block)
  def addContact(contact) {...}
  def getContact(contact_name) {...}
  def deleteContact(contact_name) {...}
end


_Problem:_

All this works wonderfully well but for one thing: once the addressbook
gives a *Contact* (actually a reference to *Contact*) to a client, the
client can modify the *Contact* (that is _inside_ the addressbook)
without the addressbook's knowledge. In effect: the addressbook's
content is open for the world to play with. Overall this could be pretty
much OK if the addressbook didn't really care about the content of
his contacts. Suppose the addressbook wants to enforce a 'no two
contacts with same name' policy ? It can't because you can always enter an
contact and change it's name afterwards (behind the addressbook's back). What if
you want to implement the addressbook as an Array of contacts sorted by
their names ? 


_Solution proposals:_


[1] The 'pass-by-value emulation' solution  
 
Emulate pass-by-value by returning a deepcopy of a contact when when
'getContact' is called. You would also have to take a deepcopy of any
contact added with 'addContact' and implement a 'updateContact(contact)'
function that allows one to supersede a contact with a new version.

Contra: to be really safe you have to implement any visitor+iterator
        pattern so that the visitor/iterator sees deepcopy's of the
        contacts.  (auch!)


[2] The 'frozen contacts' solution

Very easy: freeze all contacts that are put in the addressbook and
implement an 'updateContact(contact)'.

Contra: weird ? (feel 'hackish' to me)


[3] The 'callback' solution

When a contact is added to the addressbook, have the addressbook
register itself as an observer of the contact's name with the contact
(and have the contact notify the addressbook if it changes).

Contra: strong coupling of Contact and Addressbook class 


[4] The 'give up abstraction layer' solution

Maybe a container who's elements are easily accessible (visitor+iterator
pattern) cannot have interface decoupled with it's implementation ? This
would mean you might as well implement the Addressbook class as an
array.

Contra: - no hiding of implementation
        - 'no two contacts with same name' and other policies have to be
          implement by the clients 


What do you think ?

Simon

-- 
There are 10 types of people in the world... 
those who understand binary and those who don't.