Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Constructor API opinions

1 view
Skip to first unread message

Bob Smith

unread,
Jul 8, 2008, 10:28:04 PM7/8/08
to
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.

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?

Ben Morrow

unread,
Jul 8, 2008, 11:19:15 PM7/8/08
to

Quoth Bob Smith <nospam...@yahoo.com>:

>
> 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.
>
<snip>

> * 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.

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]

Sherman Pendley

unread,
Jul 8, 2008, 11:48:47 PM7/8/08
to
Bob Smith <nospam...@yahoo.com> writes:

> 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

bugbear

unread,
Jul 9, 2008, 5:45:13 AM7/9/08
to
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.

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

Martijn Lievaart

unread,
Jul 9, 2008, 8:04:54 AM7/9/08
to
On Wed, 09 Jul 2008 10:45:13 +0100, bugbear wrote:

> 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

Ted Zlatanov

unread,
Jul 9, 2008, 9:38:00 AM7/9/08
to
On Tue, 08 Jul 2008 19:28:04 -0700 Bob Smith <nospam...@yahoo.com> wrote:

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

0 new messages