1

Say I have 3+ types of objects:

function Sea() {
    var logs = [Logs];
    this.getLog = function(ind){return logs[ind]}
}

function Log() {
    var bumps = [Bumps];
    this.getBump = function(ind){return bumps[ind]}
}

function Bump() {
    var frogs = [Frogs];
    this.getFrog = function(ind){return frogs[ind]}
}

function Frog() {
    this.ribbit = function(){alert("Onomatopoeia!")}
}

So, Frog doesn't know about Bump, and Bump doesn't know about Log, but Log can access Bump and Frog directly and indirectly, respectively.

Now, let's say that whenever a Frog utters a ribbit, the Log moves slightly (although Frog internally doesn't care what happens outside of itself).

Now, Mrs. Demeter suggests that I don't do this:

Sea.getLog(5).getBump(2).getFrog(1).ribbit()

It reads nice, but there's some problems. Besides the issue of tight coupling, this method also makes it impossible for the ribbit to move the Log unless Frog ends up getting a reference about Log, which means the coupling gets even tighter.

However the alternative "one dot" method looks a tad atrocious:

Sea.tellFrogOnBumpOnLogToRibbit(1, 2, 5)

A reasonable solution that has been suggested here (I think) is to create a concise but tightly coupled interface to... interface, with the more business-logicy code:

function SeaInterface() {

    var sea = createSea(); //Genesis 1:10

    var logInterfaces = [LogInterfaces];
    this.getLog = function(ind) {return logInterfaces[ind]}

}

function LogInterface() {

    var log = createLog();

    var bumpInterfaces = [BumpInterfaces];
    this.getBump = function(ind) {return bumpInterfaces[ind]}

    //Private method that Frogs will know about internally:
    var move = function(){} 
}

function BumpInterface() {

    var bump = createBump();

    var frogInterfaces = [FrogInterfaces];
    this.getFrog = function(ind) {return frogInterfaces[ind]}

}

function FrogInterface(log) {

    var frog = createFrog();

    this.ribbit = function() {
        frog.ribbit();
        log.move(); //I'm allowed to do this because I'm a simple interface
    }

}

That way, I could still use chaining and make the code read well (note: chaining is not a necessity):

Sea.getLog(5).getBump(2).getFrog(1).ribbit()

And the Log would still move after a ribbit.

In the end, it's really just an attempt to minimize the detrimental affects that objects knowing about other objects can cause.

Questions:

  1. Is there an equally readable or more readable and fool-proof way to achieve the same thing (multiple objects within objects where occasionally manipulating an inner object affects an outer object)?

  2. Besides requiring more code, and the fact that the interface itself is tightly coupled (acceptable?), what other problems might arise if I were to interface with the actual object through something like this? Also... does this method have a name?

I haven't really seen many approaches like this in the wild, which is what makes me nervous.

1

I suspect your question is academic, or formal, so you might not be satisfied with my solution which is a practical one.

When you think about it, what you have is a LogConcernedWithFrogRibbits ultimately. The best way I have found to quickly decouple things is through an MVC (like PureMVC for example) which is the 'complex solution' or just go with a simple pub/sub system like Radio.js.

So the Bumps would listen for frog messages and the logs would listen to bump messages. Each message contains its sender, so the reciever can determine if the sender is an object in its collection, if not it ignores it.

All the object types you listed, their instances should probably come from a factory, so you can reference them via the factory if you wished, and all the instances should also listen for (downward) messages that will ribbit the frogs by path.

Something like: "SeaMessage", {Sea:0, Log:10, Bump:2, Frog:9000, Action:'Ribbit'}

Which would be broken down by the correct Sea, and cascaded along its way as a "LogMessage".

I mean I have to pull Einstein's Razor on this one, why beat yourself over the head? No, its not the most efficient mechanism, but this is Javascript -- what the heck are you building? haha

Its comprehensible, elegant, and easily extended. Just keep good docs on what you are doing on the message front and watch for recursion.

  • Thanks for your answer Mark. Coincidentally, I actually am experimenting with something my boss suggested which is similar to Radio.js: making ribbit fire an event which Log listens to. I'll mark this answer as accepted if it works ;) – Jeffrey Sweeney Jul 28 '14 at 14:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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