views:

114

answers:

2

Hi, I'm modelling a class diagram and I'm absolutely stuck with this issue:

My new web application has "cards" (entries about a subject) which can be modified by the users, à là wiki. But unlike wikis, different cards hold different data. Also unlike wikis, cards are interrelated with other cards explicitly in the database. Let me show you how I initially designed it using a dummy example:

/** Similar to strategy/bridge pattern */
class Card<T extends CardInfoVersion> is composed of T // container of versions
class CardInfoVersion // one version
class Painting extends CardInfoVersion 
class Museum extends CardInfoVersion is composed of Paintings

Elegant, clean, but wrong. Using this approach, museums are tied to painting versions, not to the painting itself. The first solution that came off my head was this one:

class Card<T extends CardInfoVersion> is composed of T
class CardInfoVersion
class Painting extends CardInfoVersion
class Museum extends CardInfoVersion is composed of Card<Painting>

This approach smells. Class hierarchy under CardInfoVersion is huge, so UML model would be unreadable and Card class would be filled with ORM references to CardInfoVersion subclasses. Then I came up with this:

class Card is composed of proposedModifications: Set<Card>
class Painting extends Card
class Museum extends Card is composed of Paintings

Which also smells. In fact, this is all fucked up since versioning vanishes. It also requires administrators to validate proposed modifications to cards.

I don't really know how to solve this problem. Remember: original design would be OK if CardInfoVersion subclasses weren't interrelated.

Please help!

A: 

I would take a domain-driven approach. Would your user call them "cards"? That seems to be a technical concern, but you're mixing your technical concern (Cards) with domain concerns (Museums, Paintings).

Without knowing your domain and users it's hard to take a guess at what your final solution would be.

Perhaps this:

class Museum extends Content is composed of Paintings
class Painting extends Content

class Card is composed of Set<Content>

That way you're separating your domain model (Museum, Painting), with your view model (Cards). I would even take it one step further and not use inheritance (go with the plain-old-java-object) route, but I don't know your exact implementation.

If you want more information on this style of design, this podcast is helpful.

Michael Hedgpeth
Thanks for your comment! I'll consider it.
Álvaro Martínez
A: 

@Michael has a good point. Museum is a domain object, so is Painting. It sounds like you're using the "cards" to collect various people's comments about the paintings. That suggests a CardFile is what you're trying to model. A CardFile would be a collection of Cards. A Card has a reference to the associated Museum or Painting.

Here are some hints:

  • write out some user stories or use cases. You're getting caught in programmer-thinking too early; think about what you want to do first. If you don't have a favorite way of doing this, then use this model: "Someone" "does something" "to get some result." So, for example, "I get all the cards about Magritte 'Ceçi n'es pas une pipe' in order to find out which museum has it."

  • write some "user code" for the classes. Pseudocode is fine, but it really helps come up with the interface.

So you might write:

cards := cardfile.getAllCards(ceciNesPas)
for each card in cards
do
    print card.getPainting().getMuseum()
od

I'm not at all swearing this is the best way, but an illustration.

  • If the "versioning" here is that there are many cardcs associated with the same painting, now you're set. If the format, methods, data items, on the cards are changing over time, then you need to identify what is specific to being a Card, and make that a superclass. Then you can make later versions of the Cards be new subclasses of Card: the stuff that stays the same is in the superclass, the varying parfts are the subclass's business.
Charlie Martin