|There's more than one way to do things|
A novice's thoughts on applying Demeter to extension codeby diotalevi (Canon)
|on Nov 22, 2004 at 19:52 UTC||Need Help??|
In reading Re^4: Law of Demeter and Class::DBI, I re-learned that keeping the logic near the data is a good thing. In Re^5: Law of Demeter and Class::DBI I asked how a user is supposed to attach new logic that the author of the class did not provide. There are a few ways to do this and I'm seeking your thoughts on when each alternative is more appropriate. I'm starting with the idea that putting the new logic into my own package is a poor idea because that immediately violates the principal I'm trying to understand.
How do famously popular OO languages like Java, C#, .Net, and VB handle these problems?
The rule of thumb I've learned is: Tell, don't ask. I'll quote from jplindstrom in Re^4: Law of Demeter and Class::DBI for a moment because I don't want you to decide not to read this part because it is on another page.
Assume I'm going to use this logger object and that it implements the first interface but I want to write my own code cleanly. This task probably occurs to other objects which implement reasonable APIs but for some reason just don't have the logic that I need them to. Perhaps I have an Employee object but I would like to have some logic about whether the salary is above average. This is a domain for business-level logic to show up all over the place. It won't exist in object to start with and it has to be put somewhere.
Assume also that I have a context of "here" which is some code that is using the object and a Rule of Demeter violation is involved.
Please consider the following alternates or any others you find worthwhile. I'm obviously inexpert regarding the Rule of Demeter so my perspective on what things I can and should be doing is limited. I have ordered this list by things so that the things I wish to mention and dismiss are at the start and the better solutions are at the end.
I will write code like $Employee->Manager->CostCenter and just not worry about it. This is appealing because this is what I already do and I haven't found a practical reason to stop doing this. I've never been bitten by the problems the Rule of Demeter is designed to protect against.
Wrap Demeter in a local function
I will write a locally known function which does the double dereference for me. I've now polluted my local namespace
Subclass Employee to add the function
Now I have to remember that MyEmployee is just like Employee except that I've added a property or two to it. I don't like this because there may be some other code that subclasses Employee and now I have to remember an entirely new package name. When I have multiple places to solve this problem, I end up with lots of subclassing.
I don't like it because now I have to remember more things.
This is cleaner in logic than subclassing but doesn't prevent me from having to memorize this additional class and how it relates to Employee. It also means I now have to deal with AUTOLOAD and how much of Employee's interface MyEmployee is going to have to know about.
Add the logic to the class
This is appealing because I won't have to consult with the author of the class, don't have to do complicated logic to redispatch methods, haven't played and ISA games, and it looks transparent to my user-level code. This has a namespace collision problem Employee's interface changes and adds the same function. This also enables polymorphism so if there are other unrelated objects which also implement this method, this class benefits.
Add the logic to a parallel namespace
This is also appealing but it breaks polymorphism because to get this function I have to use a special calling convention and any polymorphism-using code isn't going to know about that.