Re (tilly) 1: Loading a different Module depending on the Configuration
by tilly (Archbishop) on Sep 26, 2001 at 22:10 UTC
|
my $h = TheDb::PlainText->new();
and in TheDB/PlainText.pm have:
package TheDB::PlainText;
@ISA = 'TheDb';
use TheDb;
use strict;
# do stuff
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
# whatever is specific to a text file here
return $self;
}
# more stuff
1;
and in TheDb.pm have:
package TheDb;
# usual stuff
sub new {
my $class = shift;
my $self = {};
# Whatever initializations
return bless($self, $class);
}
It is now the user's responsibility to use the right child module for what they are doing. | [reply] [d/l] [select] |
|
|
It is now the user's responsibility to use the right child module for what they are doing.
Unless, of course, the right module needs to be determined at run time :-)
Update: I guess sometimes its just preference between doing this:
my $package = "Parent::Package::".$subpackage;
$package->method;
# And this:
Parent::Package->method($subpackage);
I see the reasoning of doing it the first way, but sometimes I just prefer to do it the second way. I started allowing it with Parse::FixedLength, and I'm not the only one, as AnyData also does that. One of the wonders (or drawbacks, depending on who you ask) of Perl is that its only as OO as you want it to be :) | [reply] [d/l] |
|
|
No unless. Method calling is fully dynamic, you don't have to hardcode the package anywhere. If you want to get abusive about it you can even do something like this:
my $pack = "Foo";
my $meth = "new";
my $obj = $pack->$meth(); # Calls method new in class Foo
So you can pass the buck to the client code, knowing that if they need to be dynamic, they still can, but it will still be simpler in the common case, and the base class will not need maintainance as you add child classes.
UPDATE
I think there is more than just a preference here. If you choose to pass the subpackage in as a string, the parent class has to do a lot more. For one thing I would now demand that it loads the child class. Which means that either the parent has to hardcode all of its children (maintainance issues anyone?), or you have to write dynamic loading logic. You have also just arbitrarily limited the naming and location of your child classes. In many cases this may be innocuous. But I don't like putting any restrictions on how things must be done unless I see very specific benefits to doing it.
Therefore I don't see the different structure as being a benefit in any way, shape, or form.
However it bears costs. You have to write more code for the feature. That is more code to write, debug, test, and be aware of. You now have objects that are not blessed into the class which people would expect them to be blessed into. It is now harder to subclass an arbitrary part of your hierarchy. Someone who wants to understand your code now has to do extra work to figure out your data structure.
This is not to say that you might not from time to time want to have dynamic loading of specific subclasses. DBI's proxying off of appropriate DBD::* classes is an excellent case in point. However such cases are somewhat exceptional. And furthermore if ever I have the choice between a minor aesthetic issue and managing to write the most naturally straightforward code possible which achieves the goal, I retrain my aesthetics! Unnecessary complications are a bad idea in my books. | [reply] [d/l] |
|
|
Re: Loading a different Module depending on the Configuration
by maverick (Curate) on Sep 26, 2001 at 21:34 UTC
|
What you're describing is (if I recall correctly) a 'factory' pattern. Try something like this (untested code)
package TheDb;
use strict;
use TheDb::PlainText;
use TheDb::SQL;
sub new {
my $class = shift;
my $type = shift;
my $full_name = "TheDB::" . $type;
return $full_name->new;
}
1;
Basically you write one package that uses in all the others. The new method for that package just creates an object of the type you ask for and returns it. Each of your 'TheDB::' object inherits from, say, 'TheDB::Base'.
/\/\averick
perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"
| [reply] [d/l] |
|
|
It's also called a 'polymorphic constructor'. I wouldn't reccomend this as good OO practice, but it's certainly ok.
------ We are the carpenters and bricklayers of the Information Age. Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.
| [reply] |
|
|
hmm,
the idea is to have the actual methods and whatever way you store and fetch stuff plugable, so, down the line I can say,
my $scheme = 'FooSQL';
my $h = TheDb->new($scheme);
And, perhaps someone else, with a different setup and wants will go:
my $scheme = 'DB_File';
my $h = TheDb->new($scheme);
having all the subclasses loaded at the same time would be incredibly wasteful and useless, since I may not know exactly what DB (or subclass module) is there.
This may seem like more work, why would you have n ways of doing the same thing? Well, you may not have a Spiffy SQL and are OK with using a plaintext solution, knowing some performance woes.
This is for a very mature, stable app, not a quick 15 minute script.
-justin simoni
!skazat! | [reply] [d/l] [select] |
|
|
This is for a very mature, stable app, not a quick 15
minute script.
<sarcasm>Heh, he he, ha HA! HAHAHAAHA!</sarcasm>
Seriously, what school of Software Engineering did you
graduate from - do you really think that using a Factory
Pattern is something that a script kiddie would come up
with? It's a very common Design Pattern.
i do appreciate your desire to write your app 'The Right
Way' - i really do, but sounds to me like you are too
worried about 'false optimization' - imagine a interstate
with a lovely 8 lane bridge that has been carefully
constructed to maximize car flow ... only to be followed
2 miles down the road by a one lane bridge that you have no
control over - that's false optimization.
You have a lot of good clues here on this thread on how to
solve your problem - take these ideas and run with 'em!
Sounds to me like a factory
pattern, or as dragonchild called it, a 'polymorphic
constructor' - is a pretty valid idea for this problem.
If you don't like that - then you might want to rack your
brain against an Abstract Factory.
But as for being concerned about loading subclasses that
won't be used for a particular run of the app - do you
_really_ need to concern yourself with that? And even if
you do - doesn't that sound like a job for the _next_
version? (nudge, nudge) ;)
jeffa
| [reply] |
|
|
Re: Loading a different Module depending on the Configuration
by tachyon (Chancellor) on Sep 26, 2001 at 22:16 UTC
|
my $DB;
$DB = new TheDB('SQL');
$DB->fetch();
$DB = new TheDB('Text');
$DB->fetch();
$DB->{'DB'} = 'SQL';
$DB->fetch();
$DB = $DB->new('Text');
$DB->fetch();
$DB = new TheDB('Oracle');
$DB->fetch();
package TheDB;
use strict;
sub new {
my ($proto, $DB) = @_;
my $class = ref($proto) || $proto;
my $self = {'DB' => $DB};
bless $self, $class;
return $self;
}
sub fetch {
if ($_[0]->{'DB'} eq 'SQL') {
&_SQL_fetch(@_);
}
elsif ($_[0]->{'DB'} eq 'Text') {
&_Text_fetch(@_);
}
else {
die "Unknown class ".$_[0]->{'DB'};
}
}
sub _SQL_fetch {
print "Using SQL method\n";
}
sub _Text_fetch {
print "Using Text method\n";
}
cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
| [reply] [d/l] |
|
|
I don't like this approach since it puts all the different saving and fetching and what have you functions in the same module, which is what I'm trying to get out of, I don't want alot of if/else statement hanging round. I want the entire system pluggable.
-justin simoni
!skazat!
| [reply] |
Re: Loading a different Module depending on the Configuration
by ducky (Scribe) on Sep 27, 2001 at 02:49 UTC
|
Well, if you were using DBI you could use DBD::CSV for the plaintext part. That way, changing the code to use a full database requires one change in the DBI->connect statement as it's already SQL.
-Ducky
| [reply] |