A more real-world case that I deal with fairly regularly is one of code portability across environments that have differing constraints. Lets consider the idea of a JSON parsing class. I know this is a solved problem, but for the purposes of illustration it may be useful.

I may have one class of servers where it is acceptable to assume that JSON::XS is available. I may have another class of servers where a recent enough Perl version is available that I can assume JSON::PP is available. So that means 5.14 or newer. And there's yet another class of servers where I cannot make any assumptions other than core Perl, and whatever code I explicitly bundle. In those environments, I have a lot of constraints that prevent me just sucking in whatever I want from CPAN (for example, tens of thousands of servers where a goal is to keep our footprint minimal).

But additionally, we have these concerns: Primary: We should use the most CPU-efficient JSON parser available. Secondary: We should use the most standardized JSON parser available. Tertiary: We should use a JSON parser that has no dependencies other than what we package and ship with our code. There is a module, JSON::Any, which handles this decision for us, but may not have the same prioritization, plus it is another dependency that I'm not guaranteed to have available in all environments. So here's a home-grown strategy to select the JSON module for us, based on the order that I might prefer for this example:

#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; { my @JSON_MODULES = qw( JSON::XS JSON JSON::PP JSON::Tiny ); my $json_class; for my $module (@JSON_MODULES) { if (eval "require $module;") { $json_class = $module; last; } } die "No JSON parsing class found. $0 requires one of ", join(', ', @JSON_MODULES), ".\n" unless $json_class; warn "Using JSON module '$json_class'.\n"; $json_class->import(qw(encode_json decode_json)); } my $json = '{"foo":"bar", "biff":["baz","buzz"]}'; print "\nData structure parsed from JSON:\n", Dumper(decode_json($json +));

If I run that on a system that has JSON::XS installed, I get this output:

Using JSON module 'JSON::XS'. Data structure parsed from JSON: $VAR1 = { 'foo' => 'bar', 'biff' => [ 'baz', 'buzz' ] };

If I run it in an environment that has neither JSON::XS nor JSON, but is Perl 5.14 or newer, I'll get this:

Using JSON module 'JSON::PP'.

If I run it in an environment that has no non-core modules, and only what I bundle with the code I'm shipping, I better be sure to ship JSON::Tiny, and if I do as I should, the output would be:

Using JSON module 'JSON::Tiny'.

...followed by my data structure dump. The point being that now I've provided flexibility that places a low burden for what modules must be packaged or available. Sure, for many environments I can just pull something from CPAN. For some, I need to have the CPAN distribution built out as an RPM, and for some, keeping the dependencies down to only what ships with the code itself may be best.

This example used a set of modules that don't require an object oriented interface, but if they did, that would be just as easy; rather than calling $module->import, I could call my $json_parser = $module->new, assuming they all implemented the same OO interface.

If you are referring specifically to the Factory pattern, the OO version I mentioned is closer to that pattern. But the Factory pattern has uses beyond only dealing with not knowing what module may be available in a given environment. The classic examples usually deal with subclasses that can't be decided at time of writing the code, but that must share a common interface with some base class, pure virtual base class, or interface role. For example, a driver needs to be able to $car->refuel, but whether the car is an instance of a Ford Van class, or a Honda Sedan class is handled by the factory.


Dave


In reply to Re: Factory classes in Perl by davido
in thread Factory classes in Perl by Bod

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.