http://qs321.pair.com?node_id=259971


in reply to Re: Short Refactoring Tip: let the object do it for you
in thread Short Refactoring Tip: let the object do it for you

BAD: if ($po->status->name eq 'Sent') ... ALMOST AS BAD: if ($po->can_send) ... GOOD: $po->send
You are breaking encapsulation in all but the last case.
How, pray tell, does a predicate function "break encapsulation"? can_send is not a getter; it reveals nothing about how the purchase order answers the question. Encapsulation is quite safely preserved.

Replies are listed 'Best First'.
Re: Re: Re: Short Refactoring Tip: let the object do it for you
by mvc (Scribe) on May 22, 2003 at 11:08 UTC

    Do you define "predicate function" here as "method that returns a boolean value"? If so, then it reveals something about the object state- information that should be encapsulated.

    What if you decide that "you can always send!". Then you have to remove the conditionals from all clients of your object. Or what if there are now 3 states for sending, each requiring a different send method? We want the clients to know as little as possible about the object. Knowing only one method, is better than knowing a method, its return type, and another method.

    "...The key question is: How much of one module must be 
    known in order to understand another module?..."
    

         Yourdon, Ed and Larry L. Constantine. Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design. (1979) On Coupling, p.85

    Breaking encapsulation here increases coupling between the clients of the object and the object itself. Note I am not saying: never use boolean methods. There may be other design forces besides "encapsulate hermetically", so we do not know which solution is best here.

    Code like: "if an object can do this, tell it to do it" smells.

      Do you define "predicate function" here as "method that returns a boolean value"? If so, then it reveals something about the object state- information that should be encapsulated.

      A predicate method (or a query method, for that matter) defends encapsulation. The existence of the method says nothing about how the target object derives an answer. It could have the answer in a hash, it could calculate it lazily, it could delegate to another object. Whatever. The point is that the client doesn't know. Coupling is kept down. And, assuming that the question lies within the province of the target object to answer, cohesion is kept up.

      I see that what you're really arguing for is reducing the need for "can you do this? yes? then do it" types of protocols. Fine; I agree. But in arguing that point, you're either misunderstanding or misrepresenting encapsulation.

        1. You are correct that reducing the need for "can you do this? yes? then do it" was what I was trying to say. This was the problem with the original solution.
        2. When I think about it (why always AFTER I post?!) you are correct in saying that I am misrepresenting encapsulation. Query methods are a tool to defend encapsulation. Getters break encapsulation. Query methods (any methods actually) increase coupling- of course the ultimately independent object has no methods, and is ultimately useless. What I was trying to say was that in our example (although it is sketchy) we can decrease coupling by dispensing with the query methods.

        So a predicate function is a boolean query method.

      Suppose you have code that says, "if object can't send email, send a fax". You end up writing an alerter-management object, then. I suppose you could keep going, but this would just create turtles all the way down until your program was nothing but objects and messages, just to avoid "scary" predicates before OO hype made this un-PC. If you want 1000 lines of code when 100 will do, be my guest.