A different part of the system uses the same class to (later) retrieve
the object from the database, by id. You can think of this app as a
small Web scraper.
I use the terminology "pull" to indicate an HTTP GET, and "retrieve" to
mean a db retrieval.
My question is, what's the best or recommended way to structure the use
of the constructor(s). For example:
my $object = MyClass->new($id);
could mean either (a) get the object from the Web and store it; or (b)
get the object from the database.
This gives me several options for how to structure the API.
* # Initially, to pull from Web
my $object = MyClass->new($id); # get from Web, store to db.
# Later, in a different part of the system ...
my $dbRetrievalObject = MyClass->new(); # returns empty object.
$dbRetrievalObject->retrieve($id);
This solution is non-symmetric -- you new() on the way in, and new();
retrieve(); on the way out.
* Or, use a flag in new(), with suitably defined constants:
my $object = MyClass->new($id, PULL);
....
my $object = MyClass->new($id, RETRIEVE);
Symmetric, but now the caller needs to know the constants.
* Or, have two different constructors:
my $object = MyClass->pull($id);
...
my $object = MyClass->retrieve($id);
Symmetric and simple, but possibly confusing because there's no
constructor called new(), and it's not immediately apparent that pull()
and retrieve() are constructors.
Opinions? Best practices?
I would have
MyClass->new(...)->pull($id);
MyClass->new(...)->retrieve($id);
(both returning the object, of course) with
MyClass->pull($id);
MyClass->retrieve($id);
shortcuts that call 'new' with default parameters. You can test if
you're being called on the class or an object with 'ref', so
something like
sub pull {
my ($self, $id) = @_;
ref $self or $self = $self->new;
...
}
Ben
--
You poor take courage, you rich take care:
The Earth was made a common treasury for everyone to share
All things in common, all people one.
'We come in peace'---the order came to cut them down. [b...@morrow.me.uk]
> I have a class that is used two ways: given an id, it pulls an object
> from a web page identified by id, and stores the object in a database.
>
> A different part of the system uses the same class to (later) retrieve
> the object from the database, by id. You can think of this app as a
> small Web scraper.
>
> I use the terminology "pull" to indicate an HTTP GET, and "retrieve" to
> mean a db retrieval.
>
> My question is, what's the best or recommended way to structure the use
> of the constructor(s). For example:
>
> my $object = MyClass->new($id);
>
> could mean either (a) get the object from the Web and store it; or (b)
> get the object from the database.
Could your new() method check the database first, and retrieve the
object if it's there, and pull it from the web if not?
sherm--
--
My blog: http://shermspace.blogspot.com
Cocoa programming in Perl: http://camelbones.sourceforge.net
I think THAT is your problem; you have one class doing two things.
If the retriever needs DB information, you should pass
an instance of a DB class to the retrieve constructor.
If you simply need to share utility methods
between your two pieces of functionality
they can either both take an instance
of a class with the methods in, or share
a base class.
BugBear
> Bob Smith wrote:
>> I have a class that is used two ways: given an id, it pulls an object
>> from a web page identified by id, and stores the object in a database.
>
> I think THAT is your problem; you have one class doing two things.
May be, may be not. But it is absolutely the correct question to ask.
> If the retriever needs DB information, you should pass an instance of a
> DB class to the retrieve constructor.
>
> If you simply need to share utility methods between your two pieces of
> functionality they can either both take an instance of a class with the
> methods in, or share a base class.
Or create a data class and create separate classes that do the IO.
# error handling omited
my $retr = Retriever->new($optional_proxy_info);
my $obj = Retriever->get($url, $additional_parms);
my $db = $DBIO->new($database_info);
$db->write($obj);
(When faced with inheritance, think hard about doing it another way.
Inheritance is a good tool, but is way overused.)
M4
BS> I have a class that is used two ways: given an id, it pulls an object
BS> from a web page identified by id, and stores the object in a database.
BS> A different part of the system uses the same class to (later) retrieve
BS> the object from the database, by id. You can think of this app as a
BS> small Web scraper.
BS> My question is, what's the best or recommended way to structure the use
BS> of the constructor(s). For example:
BS> my $object = MyClass->new($id);
BS> could mean either (a) get the object from the Web and store it; or (b)
BS> get the object from the database.
I like the Rose::DB::Object approach (and you could just inherit from
that class). You create the object with new() but it's not saved in the
database until you call save(). You also need to call a load function
(there's a bunch, you can search or get a specific table row) to load
the object from the database. So logically you have the data structure
you're looking for, filling in data from the web site, but then at a
later point you can choose to save() it or not.
I would structure things so $id is your PK in the appropriate table.
Rose::DB::Object supports table relationships, so you can use multiple
tables as needed.
Ted