osunderdog has asked for the wisdom of the Perl Monks concerning the following question:

Perlmonks, I have a matter for your consideration:

I am looking for a pattern for a Class Factory Method pattern in perl. I am developing a class that I expect to have at least three subclasses that can be instanciated. The base class will define the interface and each of the subclass will provide a different implementation for the platform where class is invoked. I have written several of these, but each time I wonder if there is a pattern out there that avoids some of the pitfalls or, worse yet, there are pitfalls have yet to encounter!

I know that there is a Package to do this via inheritance: Class::Factory  However I do not have access to that Class in our standard Perl installation and I would like to minimize external dependencies.

For the base class, here's what I have:

package ProcInfo; use Carp; use strict; use warnings; our $VERSION = '0.01'; sub new { my $class = shift; my $self = {}; bless $self, $class; $self->_init(); return $self; } sub _init { my $self = shift; my $osModule = "ProcInfo_$^O"; # Load the subclass if it isn't already loaded. eval "require $osModule"; if($@) { croak "Could not load OS ProcInfo Module:$osModule. [$@]"; } # rebless self using subclass. bless $self, $osModule; $self->_init(@_); return $self; } sub method_1 { return 1; } 1;

Some question I have about the base class implementation:

The skeleton for each sublcass would looking like this and it would be stored in ProcInfo_linux.pm:

package ProcInfo_linux; use strict; use warnings; use base qw|ProcInfo|; our $VERSION = '0.01'; sub _init { my $self = shift; return $self; } sub method_1 { return 1; } 1;

Finally, here is my test script (ProcInfo.t):

use Test::More tests => 3; BEGIN { use_ok('ProcInfo') }; my $pInfo = new ProcInfo; is(ref($pInfo), "ProcInfo_$^O", "Factory new Works"); ok($pInfo->method_1());

Any suggestions or comments on this implementation would be appreciated!


"Look, Shiny Things!" is not a better business strategy than compatibility and reuse.


OSUnderdog

Janitored by Arunbear - added readmore tags, as per Monastery guidelines

Replies are listed 'Best First'.
Re: Perl Factory Method Pattern?
by dragonchild (Archbishop) on Oct 11, 2004 at 19:42 UTC
    ... and I would like to minimize external dependencies.

    That is a feeling that many share, but I don't think it is worthwhile. CPAN exists so that the mainline distribution of Perl doesn't bloat to 10G, 90% any given user will not need. Most of the applications you can think of in Perl require at least 10-20% of their module code to be downloaded from CPAN. For example, one of the most downloaded module from CPAN is DBI. If CGI wasn't in the mainline, it would be the most downloaded module.

    Download Class::Factory and just deal with it. CPAN isn't an external dependency - it's one of the primary reasons Perl is worth using.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      I agree that one has to deal with CPAN more or less, but it is quite normal to have concerns over quality.

      A mudule like DBI, as you said, is one of the most downloaded module. What does that mean? that means that it gets a better chance to have bugs found, and fixed because of all the attention it attracted. This creates a positive cycle, it is getting better, so more poeple use it; more people use it, so it gets even better...

      I am not sure about Class::Factory, but in general, it is always a good idea to ask for others' experience with a CPAN module before you use it, or the other way around, try it, and share your good or bad experience with others.

Re: Perl Factory Method Pattern?
by sandfly (Beadle) on Oct 11, 2004 at 22:51 UTC
    To answer the questions you actually asked, in reverse order:
    • Yes, this is the way to rebless into a new class.
    • The way you've coded the "new" method, it calls _init using a method call on $self. It needs to be blessed for this to work. You could change this to a simple subroutine call: _init( $self ), and not bother with the first blessing.

    What you've coded will work, and most of it is fine; but there are a couple of things I dislike about the class structure you've used:

    • First, you have two _init methods, which do different things: one is a factory method; the other is a genuine instance initialisation.
    • Second, your base class, ProcInfo, has two roles: first, it's a factory; second, it's a ProcInfo thingy.
    You've said you have written a few of these; if you put the code from _init into a separate module, called, say, Factory, in a method called something like "makeOSSpecific", you can get reuse. The first parameter would be the base class name, so you'd call it from "new" something like: return Factory::makeOSSpecific( "ProcInfo", $self ). There would be no need to include Factory in the class hierarchy, you'd just require or use it in ProcInfo.
Re: Perl Factory Method Pattern?
by SpanishInquisition (Pilgrim) on Oct 11, 2004 at 20:10 UTC
    CPAN is no more an external dependancy than is having the right version of libc or the latest security patches to SSH...you have to be able to deal with these things. Plus, you can always download/install a local copy to your home directory (or any directory) and check it in to version control if you have a problem with deployment in network-constrainted environments.

    as to the OOP question, my stance on design patterns is another story... Dominus is more eloquent than I, and he bites his tongue more too: Design Patterns Aren't

      I think you misunderstood MJD's presentation (which is quite common, as he expresses at the addition he made to the end of the talk on the web).

      MJD is not saying Design Patterns are good or bad. He's saying there is a conflict of terminology, and we may be missing out on some really useful stuff because of it.

      "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

        I understood. "Design Patterns" in the C++ sense is what this post is pretty much about, not "Design Patterns" in the architectural sense. His point about such things being inhuman (first several slides) were right... Agreed, they have value, but they have value in the common terminology sense, i.e. knowing what a Factory is, rather than having the template to implement a Factory.
Minimizing dependencies (was: Perl Factory Method Pattern?)
by lachoy (Parson) on Oct 13, 2004 at 00:40 UTC

    Just a few words on minimizing dependencies:

    Having to download/build dependencies is a complaint a lot of people have with large modules/applications on CPAN. I don't personally agree with not using a module because of dependencies-- especially a pure-Perl module! without additional dependencies of its own! -- but you should at least realize that you're making a number of trade-offs by doing so.

    • This module has been on CPAN for nearly four years, and has been exercised by lots of people in lots of situations on lots of platforms. Yours is brand new and barely tested.
    • Chances are those additional features in the module are there for a reason; if you continue to improve yours for a while you'll probably see why.
    • Because it's written for public vs. private consumption I'm guessing it has much better documentation than you're going to write, which makes it easy for the person reading your code six months from now to figure out what's going on. Even if that person six months from now is you.

    I'm not saying anything bad about re-creating functionality to learn how it works because I learn by doing too. Going through the trials of typing in code, debugging it, thinking about ways to break it is a great way to learn. (And I've been known to recreate some wheels as well...) But CPAN is such a fantastic resource that it seems a shame to dismiss it because you'll have to mount the wheel yourself :-)

    And yes, I'm the Class::Factory author, so I'm a little biased :-)

    Chris
    M-x auto-bs-mode

      It's a great library and I'm going to end up using it. I'll just add it to a local package collection.


      "Look, Shiny Things!" is not a better business strategy than compatibility and reuse.


      OSUnderdog