the factory method and the constructor (which the factory would use) would both be methods of the same class

In theory, it'd be possible for this "constructor" to return an object of a different class. But I don't see why the constructor would need to be a member of the factory class?

Anyway, here's my interpretation of your description. Note how Object still has a formal new constructor, but it could be documented that users should not call it directly, but use Factory methods instead - it could even be named _new to make that even more clear.

use warnings; use strict; package Factory { sub new { my ($class,%args) = @_; my $self = { config => _read_config( $args{config_file} ), }; return bless $self, $class; } sub _read_config { my $file = shift; my %config; # ... return \%config; } sub make_object_from_data { my ($self,$data) = @_; my %args; # complex code to build %args from $data using $self->{config} return Object->new(%args); } } package Object { sub new { my ($class,%args) = @_; my $self = \%args; return bless $self, $class; } # ... } my $factory = Factory->new( config_file => "file.xml" ); my $obj1 = $factory->make_object_from_data( { foo=>123 } ); my $obj2 = $factory->make_object_from_data( { bar=>456 } );

However, looking at this, here's how I might have structured this code. It has the advantage that "Object->new" isn't hardcoded, making subclassing of that class easier. To me, it feels more in line with the requirements as far as you've described them.

use warnings; use strict; package Config { sub new { my ($class,%args) = @_; my $self = {}; # code to read $args{config_file} into $self return bless $self, $class; } } package Object { sub new { my ($class,%args) = @_; my $self = _parse_data_with_config($args{config},$args{data}); return bless $self, $class; } sub _parse_data_with_config { my ($config, $data) = @_; my $self = {}; # complex code to build $self from $data using $config return $self; } # ... } my $config = Config->new( config_file => "file.xml" ); my $obj1 = Object->new( config => $config, data => { foo=>123 } ); my $obj2 = Object->new( config => $config, data => { bar=>456 } );

Of course it'd be possible to add a method to Config like this:

sub new_object { my ($self,$data) = @_; return Object->new( config=>$self, data=>$data ); } # ... call as: my $obj3 = $config->new_object( { quz=>789 } );

... and you'd have something very similar to my first example.

As you can see, I've put the "complex code" into a sub in each case, and as you can tell, except for the variable names, these subs could be pretty much identical in both examples. This means that the surrounding code could be refactored more easily if you decide that a different API makes more sense. Unless you've got more complex requirements you haven't told us about, I'd suggest just starting with one API - once you actually start using your own API you will quickly notice whether it is good or a different API would be better. And if you've structured your code in a way that makes refactoring easier, you'll be less hesitant to do so.


In reply to Re^3: Using a factory class to return objects of the same class by haukex
in thread Using a factory class to return objects of the same class by Amblikai

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.