Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.
    ------------- 1    * -------------- *       1 --------
    | Container |--------| Assignment |-----------| User |
    -------------        --------------           --------
          ^                     ^
          |                     |
      ----------            -------------
      |        |            |           |
---------- ----------  ---------- ---------------
| Flight | | Dinner |  | Booking| | Reservation |
---------- ----------  ---------- ---------------

This problem is one that I've stumbled upon in several different occasions but never found an elegant solution for:

In my system model (in rails), which maps to the database, I need to have Users that can be added to Containers through Assignments.

Now, there can be many things that can be containers:

  • A Flight is a Container. It can hold Users. In such a case the concrete Assignment is a Booking.
  • A Dinner is a Container. It can hold Users. In such a case the concrete Assignment is a Reservation.
  • And many more. You get my point.

So I have Abstract notions of Container and Assignment. Containers hold Assignments and I also have concrete implementations of them, with each concrete implementation of Container matching a concrete implementation of Assignment. The straight forward design is as above. My main problem with it is that it doesn't express the relation between each concrete container and the concrete assignment.

Any ideas how to better design this?

share|improve this question
1  
Having something like flights and dinners in one and the same table looks rather ugly. Is there any serious relation between the two in your App other than the abstract notion of both of them being "containers"? –  thorsten müller Mar 21 '13 at 16:17
    
Offhand, it sounds to me like an IContainer (an interface, where you have different underlying implementations). –  Robert Harvey Mar 21 '13 at 16:22
    
I'd give Flight a property Bookings and a property Users, where Users is a convenience feature. I'd mostly abandon the notion of Container and Assignment, but if you really want you can use interfaces(IContainer with property IEnumerable<IAssignment> Assignments to represent them. –  CodesInChaos Mar 21 '13 at 16:22
    
@CodesInChaos: Polymorphic containers aren't exactly unprecedented. You need them for an "activity list," for example, which can contain calendar, todo and project activities. –  Robert Harvey Mar 21 '13 at 16:24
    
@thorsten müller I see your point. However, the main theme of my application is the assignment of users to various 'things'. These things may be very different in the real world (as flights and dinners), and the relations to the users may be different as well, but most of the logic of the system is related to this containment, so for the system, they are very similar. I wouldn't want to duplicate it for each. –  davidrac Mar 21 '13 at 16:31
add comment

1 Answer

You've actually got a basic implementation of the Bridge Pattern.

Where things break down is that a Dinner shouldn't contain a Booking. However, your model indicates that it can. From your comments, you indicated that there is a lot of shared logic in the Container class that works on a collection of Assignments.

I am going to assume that the Assignment class performs its work using template method to delegate implementation details to the sub-classes and that Container doesn't need to be aware of which Assignment type it is working with. In this case, the only concern is limiting what types of Assignments can be associated with a Container.

In a typed language, you could create a "protected" addAssignment method in the Container class. Then in each Container subclass provide a public type-safe addReservation or addBooking method that just calls the protected addAssignment. You could enforce this will a runtime check in a dynamic language, but this seems like overkill.

Another solution is to recognize that both Booking and Reservation contain a single User. Technically you could create an "abstract" method in the Container called addAssignment accepting a User rather than an Assignment. The Container sub-classes then "override" the method by decorated the passed User object and adding to the underlying collection.

My point is that there are a lot of options, which might change on the way your objects are interacting. For instance, you could even pass an AssignmentFactory to the Container that moved the creation logic somewhere else. You really have to decide to what level of control you want over your code. With a dynamic language it is a little more difficult to make explicit. I hope at least some of my examples also demonstrated just how over-engineered a solution can be when you start being paranoid.

share|improve this answer
    
Thanks you for the detailed suggestions. Putting the creation logic in the container class/subclass may help a bit. I agree to your point about over engineering things. –  davidrac Mar 22 '13 at 5:40
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.