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

Inheritance is one way to go, but it should only be used when there is a clear inheritance relationship between the objects being modeled. A more common solution would be to just put the shared code in a separate utility class and have the other classes use that.

Replies are listed 'Best First'.
Re: Re: Re: OOP - Sharing class methods
by pdcawley (Hermit) on Aug 15, 2002 at 13:42 UTC
    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...
      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...