views:

167

answers:

5

Something keeps showing up in my programming, and it is that two things are the same from some viewpoint, but different from another. Like, imagine you build a graph of rail stations, connected by trains, then the classes Vertex and RailStation are sometimes the same, other times not.

So, imagine I have a graph that very much represents rail stations and trains. Then I hand this graph to another object, which deletes some vertices, and then I want the corresponding rail stations to be gone.

I don't want to make rail stations "properties" of vertices, they're not. Also, the problem is symmetrical: If I erase a railstation, I want the corresponding vertex to be gone. What is the proper OO way to model or correspondences. I'm willing to go a few extra miles by writing some support methods or classes, if in the end the overall usage is simple and easy.

I'm currently using the Smalltalk programming language, but the question isn't really smalltalk-specific, I think. I just mention it because in Smalltalk, you can do cool tricks like examining the call stack, which might be helpful in this context.

Update: Well, RailStations aren't Vertices! Are they?

Ok, let us consider real code, as demanded in the answers. Let me model a person with children. That's the easiest thing, right? Children should also know their parents, so we have like a doubly linked tree. To make disbanding parents from children easier, I model the link between parent and child as a Relationship, with properties parent and child.

So, I could implement parent>>removeChild: perhaps like this

removeChild: aChild
    (parent relationshipWith: aChild) disband.

So, a parent has a collection of relationships, not of children. But each relationship corresponds to a child. Now I want to do things like this:

parent children removeAllSuchThat: [:e | e age < 12]

which should remove the relationship and the child.

Here, relationships and children correspond in some sense. So, what do I do now? Don't get me wrong, I'm fully aware that I could solve the problem without introducing Relationship classes. But indeed, parents and children actually do share a relationship, so why not model that and use it to help disbanding double links less imperatively?

+3  A: 

In your problem domain, aren't stations a kind of vertex? In which case, why not derive Station from Vertex?

Notice the use of the phrase "in your problem domain". Your problem appears to be about the use as railway stations appearing in a graph. So yes, in that domain, stations are vertexes. If it was a different problem domain, say a database on railway station architecture, they may well not be. Most modern languages support some idea of namespaces to allow you to have different kinds of entity with the same names in different domains.

Regarding your parent/child problem, once again you are being too general. If I were modelling mathematical expressions and sub expressions, if I remove a parent I would want to remove and delete/free all subexpressions. OTOH, ff I were modelling legal responsibility relationships in the UK population, then when a responsibility isis dissolved (say because of a divorce), I only want to remove the relationship, and NOT delete/free the child, which has its own independent existence.

anon
Well, as for the children thing, in some contexts they correspond, in others they don't. That is entirely my point, which why I'd refrain from simply using inheritence. It depends on the context if to identify or not. Isn't there a modelling that serves contexts? If I am within a context of correspondance, how do I model that correspondance? One idea I've had was making a special kind of identifying collection, which contains pairs of Railstations and Vertices, and can be switched to serving either Railstations or Vertices. Deleting a RailStation would thus delete the vertex too.
nes1983
And, of course, by removing a child, I mean: removing it from its parent. Not out of the system.
nes1983
As I said in my answer, you are trying to make one solution for two different problem domains. Except for very basic types such as integers, strings, lists etc. this is rarely a good idea.
anon
+2  A: 

It seems like you just want RailStation to inherit from Vertex (is-a relationship). See this smalltalk tutorial on inheritance. That way, if you have a graph of RailStations, an object used to dealing (generically) with graphs of Vertexes would handle things right naturally.

If this approach won't work, be more specific (preferably with real code).

Matthew Flaschen
+2  A: 

From your description of the problem, you have a one-to-one correspondence of stations to vertices and deleting a station should automatically delete the corresponding vertex (and vice-versa). You also mentioned building "a graph of rail stations, connected by trains", by which you apparently mean a graph in which stations are vertices and trains are edges.

So, in what way is a station not a vertex? If the station does not exist except as a vertex, and if a vertex does not exist except as a station, then what benefit do you see in maintaining them as two distinct-but-linked entities?

As I understand your situation, station-isa-vertex and inheritance is the way to model that.

Dave Sherohman
Well, the railstation thing is really just an example. It happens to me over and over that I come across correspondances and don't quite know how to handle them, and while with the railstations, inheritence offers a cheap way out, it always feels cheap and cheaty. If I build a graph of Seaside components, I'm not sure if I want to change the complete Seaside hierarchy. What I really want is to glue things together in some context, and leave them separate in other contexts.
nes1983
In that case, it sounds like a job for aggregation/delegation - railstation/seaside has-a vertex, which is created in the rs/ss constructor and destroyed by its destructor. You just need to remember not to manually destroy the vertex in that scenario, unless you create an OwnedVertex subclass which notifies its owner before dying so that the rs/ss can self-destruct along with it.
Dave Sherohman
+1  A: 

Having a Relationship object is a good idea.

I think the appropriate question here is "which use should be made of it?".

Probably Parent and Child classes are extending the same Person superclass, so they'll have some attributes in common, age for example.

In my idea, I can see the following: Parent and Child objects have to know each other, so both classes have to keep a link to the same Relationship. The Relationship object keeps a one-to-many relation between a single parent and a certain number of children, and it'll keep a reference to each Person object.

This way you can implement the whole disbanding logic within the Relationshp object, more or less sophisticated as you wish. You can query the Relationship object to know which members of the family match your requirements to do something. You can make the relationship to disband (and destroy) safely, as it will know all members and would ask them to break the reference and then it would be ready to destroy, or ask to some member to leave the family, keeping the Relationship object alive.

But that's not all. Relationship should be really a superclass, extended by HierarchicalRelationship and PeerRelationship (or FriendRelationship).

This specialization lets you have Parent(s) and Child(ren) to link between other hierarchies in a completely traversal way.

The true concept behind this is that your Relationship objects are the key to query and organize the whole bunch of Person objects (or Vertex objects) in a scalable and structured way, so the whole data domain you end up with is usable in any sense you like, whether you want to disband groups or walk a certain path (or railroad) between them.

Sorry for the huge amount of metaphores.

Scarlet
Actually, I very much agree to your way of thinking, it clears up a lot that I've had on my mind. I still don't exactly know HOW to do that, but yes, I do see the implication on queries (in fact, this is how I got to the question in the first place).
nes1983
Ok Niko, let me know if you need more help. I don't know Smalltalk, but Objective-C and C++ instead. Maybe we can as well express OO concepts without direct language implications.
Scarlet
+1  A: 

Take a look at Fame, see http://www.squeaksource.com/Fame.html

We use a specialized subclass of Collection that updates the opposite end when you add or remove elements. Also, you can annotate your classes with pragmas to annotate relations. These pragmas are used by the Fame framework to do all kind of nice stuff.

Adrian