Austin Hastings writes:
> Suppose that I have, for example:
> 
>   class Session {
>     has @:messages;
> 
>     method clear_messages() {...}
>     method add_message($msg) {...}
>     method have_messages() {...}
>     method get_messages() returns Array {... font color="black" ...}
>   }
> 
> And suppose I add to it:
> 
>   class Session {
>     has @:messages;
> 
>     method clear_messages() {...}
>     method add_message($msg) {...}
>     method have_messages() {...}
>     method get_messages() returns Array {... font color="black" ...}
> 
>     has @:errors;
> 
>     method clear_errors() {...}
>     method add_error($msg) {...}
>     method have_errors() {...}
>     method get_errors() returns Array {... font color="red" ...}
>   }
> 
> So I realize that not only is the whole list-of-messages thing a packageable
> behavior (read: Role or Class) but that this particular behavior recurs
> within my class.

So what you want is a role whose names are private to the role, not the
aggreagating class.  Well, I believe private (i.e. $:foo) variables do
that anyway, so you can just abstract your messages out into a role and
it will work fine.  But if you read on, I'll offer some unsolicited
design advice.

> One solution is to compose member objects that implement this behavior:
> 
>   if ($my_object.messages.have_messages) {...}
> 
> But that sucks.

Why?  From a design perspective, that's the correct way to do it.  What
if you have a routine that operates on message lists -- pruning them or
somesuch.  If you do it by renaming the methods, you break any kind of
future-proof code reuse that abstracting gets you in the first place.
But I'll agree that:

    if $my_object.messages.have_messages {...}

Kinda sucks.  But you'll find that things that suck in this particular
way can be solved by tersifying your method names.

    class MessageList {
        method ready() {...}
        method add($msg) {...}
        method clear() {...}
        method get() {...}
    }

There's no reason to repeat _message on the end of each method when
you're already in a class about messages.  And then you have:

    if $my_object.messages.ready {
        say for $object.messages.get;
    }

Which is quite more tolerable, IMO.

But this isn't an OO design list, it's a language design list.

If it turns out that role private variables leak, I might suggest making
a MessageList class as above, then making a role that knows how to turn
a MessageList into a set of methods.  Then you'd pass the role the
MessageList object which you instantiate yourself, and it would generate
the methods for you.  That's kind of a kludge, but you're using roles
for something they're not really intended for, so that's what you get.
Keep in mind that there are plenty of other ways to do what you want;
this is Perl, after all.

Luke

Reply via email to