in reply to Re: Re: OOP - Sharing class methods
in thread OOP - Sharing class methods

How you make use of your utility class is somewhat interesting though. The naïve approach can lead to problems down the road when you make a subclass and it needs to have a slightly different version of some or all of the methods provided by the utility class.

Here's a naïve implementation:

package Foo; use UtilityClass; sub some_method { my $self = shift; $self->UtilityClass::some_method(@_); }
Nothing wrong with that, is there? Well... yes, because stuff is hardcoded, you may find that, when you come to subclass foo, things will break. A better approach is:
package Foo; use UtilityClass; sub helper_class { 'UtilityClass' }; sub some_method { goto &{ $_[0]->helper_class->can('some_method') }; }
You could go further and add per object customization, by turning 'helper_class' into an instance method, allowing you to choose which utility class to use on an object by object basis rather than class by class...

Replies are listed 'Best First'.
Re: Re: Re: Re: OOP - Sharing class methods
by perrin (Chancellor) on Aug 15, 2002 at 17:45 UTC
    I didn't see any mention of proxying methods off to this other class. I interpreted the question as one of how to share some common functionality, not how to pass method calls off to a different class.

    Since we're doing OO and therefore concerned about inheritance and such, the utility class should be an actual class and use class methods:

    package Foo; use UtilityClass; sub bubbles { ...class-specific stuff... UtilityClass->buttercup(); ...class-specific stuff... }
      The problem there is that you've hardwired the Utility class's name into your class. Suppose you want to subclass Foo to use a different UtilityClass (or a subclass of it), with the hardwiring you have in place you have to override all the methods that make calls to the utility class.

      At the very least you should wrap the Utility classname in a method, so your code becomes:

      package Foo; use UtilityClass; sub helper { 'UtilityClass' } sub bubbles { ... $self->helper->buttercup(); ... }
      Et voila! you'll only have to change the utility class name at two points in your subclass; no need to override.

      Actually, I wonder if you couldn't use the Exporter to implement something like a ruby mixin.

      package UtilityClass; use base 'Exporter'; @EXPORT = qw/buttercup/; sub buttercup { my $self = shift; # $self is *not* a 'UtilityClass'; ... }
      You know, I'm not sure whether that's a good idea, or a barking mad one...
        Suppose you want to subclass Foo to use a different UtilityClass

        Well, if that happened, and there was nothing else in the subclass that would cause me to override these methods, then I would do what you've suggested. However, that's a pretty unlikely scenario and I don't see any reason to add the extra complexity until it's actually needed. My opinion is that the code should stay as simple as possible until the requirements demand it be more complex.

        I've also seen this sort of technique used for runtime configuration (e.g. use Storable or Data::Dumper for serialization), but that doesn't seem to be called for here.