开发者

"Message Chains" vs "Middle Man"

I'm reading through Fowler's refactoring book and am a bit confused about those two code smells.

"Message Chains" are calls like a.getB().getC().getValue().

"Middle Man" is a method like

class A
{
    object getCValue()
    {
        return b.getCValue();
    }
}

The way I understand the two section is that if you've got "Message Chains" you shorten them by introducing "Middle Men". And If you've got "Middle Men" you turn them into "Message Chains"...

Now obviously there has to be some limitation to this or you'd have a programmer's merry-go-round. At what point should I favor开发者_开发问答 one over the other?

One is coupling the class to unrelated classes, the other is coupling the class to the structure. So in theory my approach would be to check if any given change reduces one kind of coupling more than it increases the other kind of coupling. But is one kind of coupling worse and should be weighed more? I.e. only add one class coupling if you can remove X structural couplings?


Preferring middle men over message chains is also known as the Law of Demeter, which can be summarized as "only talk to your direct dependencies".

One benefit of using middle men instead of message chains is that you have to provide fewer mocks when doing unit testing. Classes become really hard to test when you have to provide mocks not only for their direct dependencies but also their indirect ones.

It also helps with separation of concerns, as code that has an A and wants a C should not have to know that there's a B involved. This helps modularity.

The main argument for message chains is that you don't have to write the boilerplate in the middle, and it might make sense in some cases, but I think the rule of thumb should be to prefer middle men.


As Hammar said, this one is all about the Law of Demeter. Things like a.getB().getC().getD() are pretty much always bad. They introduce coupling to the client of the A interface. Prefer to introduce a middle man, such as:

class A
    def calculateHowManyCowsCanFitOnTheMoon
        doLocalCalculation(b.performEncapsulatedCalculation())
    end
end

You want to get rid of the Middle Man when it's not serving a purpose like the above, such as when it's just pulling data from B. I'd go so far as saying that the refactoring for a bad Middle Man might be the Move Field/Move Method refactoring.


It's your choice. Code it in the way that you think will be more maintainable. BTW, I don't think that there is a case of "coupling the class to unrelated classes". Rather, it is a matter of turning an indirect relation into a direct relation. This is particularly worth doing when you access the indirect class multiple times from your class. This might also remove some dependencies on intermediate classes, depending on how you establish the direct relationship.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜