Discussions

News: Creating Courtesy Implementations

  1. Creating Courtesy Implementations (8 messages)

    Martin Fowler is discussing Courtesy Implementations, especially for use with the Composite pattern. He also has some advice for making sure resource pools are closed.

    Testing Resource Pools: Quick Tip
    Many applications use resource pools - a good example is connection pools for database connections. Teams often get into trouble because people forget to release the resource back to the pool when they are done with it. As a result you get resource leaks.

    To help spot these in testing, make sure you set the resource pool size to 1 in your tests. That way if some code doesn't release its resource the next test that uses that resource will fail, and you don't have too far to look for the culprit.
    Of course, you can have mocks for the pools which keep counts and tell you when you have been bad too :)

    Read about Martin's Courtesy Implementation
  2. Creating Courtesy Implementations[ Go to top ]

    Courtesy Implementation seems to me like something that should be used as a last resort, and can usually be avoided with a simple refactoring.

    I found the example a little fuzzy and in the wrong language :), so I am going to change it up slightly.

    public abstract class Node()
    {
        public abstract int getContainedElephants();
    }

    Fowler's argument is that to avoid some smelly instanceof conditionals, we should create a courteous (but nonsensical) implementation of this method in the subclass Elephant.

    However, I have found that this situation can usually be resolved with a simple Rename Method refactoring that makes the method generalizable enough to encompass all of the subclasses. Sometimes the method name might get pretty long, but you end up with no instanceof and no nonsense implementations.

    In this case, I believe the problem could be resolved as so:

    public abstract class Node()
    {
        public abstract int countElephants();
    }

    I think this method name makes sense for both a box and an elephant. If you disagree, you can certainly come up with your own name.
  3. Creating Courtesy Implementations[ Go to top ]

    Excuse the follow-up note:

    If you can't come up with a reasonable method name that makes sense for all of the domain subclasses, then I think there is a pretty good argument that the method does not belong in the base class.

    In such a case, I would probably apply the Push Down Method refactoring before creating a Nonsense Implementation.
  4. in the article, Fowler uses the method name num_elephants. Following Java naming conventions, this would be getNumElephants(). I wouldn't want to argue one way or the other as to whether countElephants() is better or worse than getNumElephants(). However, I do agree that either of these names would be superior to your example of getContainedElephants(), because one might expect that a method named getContainedElephants() would return a collection of all the contained elephants. After reading the article, I believe that fowler was more concerned with the implementation of the method, rather than with the name of the method.

    As for your subsequent point: that if you can't come up with a good name you should consider pushing the method down into a subclass. Well, if you did that, you would no longer be able to use the polymorphic method call that is essential to the pattern that he was demonstrating.
  5. What is the big deal?[ Go to top ]

    Doesn't seem very profound to me! Fowler says Elephants cannot contain Elephants. Why not? After all, the elephants are virtual. Doesn't it all depend on how you define the "Contains" operation?
  6. In these heterogeneous compositions, the approach of sending an object visiting the nodes seems to be a better approach.

    For example,

    public class Box
    {
       public void answerSurvey(Question q)
       {
           //pass buck to contained elements
       }
    }

    public class Elephant
    {
       public void answerSurvey(Question q)
       {
          //answer the question
       }
    }


    Further, the classes can decide which questions they might have an answer to. Now, does that situation involve a "switch-case"? In some way yes. But only limited to the extent of knowing which questions can be answered by the class - making all others unanswerable.

    It is possible to avoid that switch-case by passing the buck back to the Question and using polymorphic calls.

    public class Box
    {
       public void answerSurvey(Question q)
       {
           question.extractAnswer(this);

           //pass the buck to contained elements
           for(...)
       }
    }

    public class Elephant
    {
       public void answerSurvey(Question q)
       {
           question.extractAnswer(this);
       }
    }


    public class Question
    {
        public void extractAnswer(Elephant elephant)
        {
            elephantCount++;
        }

        public void extractAnswer(Box box)
        {
           //leave elephantCount unchanged
        }
        
        public void extractAnswer(Object other)
        {
            //dont care
        }
    }
  7. Of course the Questions themselves are a hierarchy and the various polymorphic "extractAnswers" are spread across it...
  8. Creating Courtesy Implementations[ Go to top ]

    <pendant mode>

    There's no need to suspend belief:

     a<sup>x</sup> / a<sup>y</sup> = a<sup>x-y</sup>, a != 0

     So, 5 / 5 = 5<sup>1 - 1</sup> = 1

    </pendant mode>
  9. traversal objects[ Go to top ]

    Is Martin only reinventing the wheel?

    I think this problem and possible solutions are well addressed by the Demeter's law (look at http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/navigation-control/apply-LOD.html)

    Fowler sads:
    "After all we are making the test because elephants can't contain boxes or elephants, so it doesn't make sense to ask them how many elephants are inside them."

    In the new model we can't have a pregnant elephant...