(jeffa) Re: OO Application Design
by jeffa (Bishop) on Sep 25, 2002 at 04:41 UTC
|
getAdults() sounds like a specific version of, say,
a search() method:
# warning, not what you really need
my @adult = Person->search(age => 18);
which is more than likely a class method. Say, you aren't
rolling your own are you? Check out Class::DBI
and it's oh so useful extension,
which allows you to do things like:
@adult = Person->retrieve_from_sql('WHERE age >= ?', 18);
which is what you really most likely want (you could also
wrap that code in the method getAdults()).
jeffa
L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)
| [reply] [d/l] [select] |
|
I did something fairly similar recently - to paraphrase my POD (Yay! I'm so glad I wrote it now :-) ):
Person->get(name => "Foo Bar");
Person->get(name => {method => "EQUALS", value=>"Foo Bar"});
Person->get(name => {method => "REGEX", value=>"Foo? Bar"});
Person->get(name => {method => "CONTAINS", value=>"Foo"});
Person->get(age => {method => "GREATERTHAN", value=>18});
Person->get(age => {method => "LESSTHAN", value=>21});
Where the arguments to the get function acted as constraints, i.e. reducing the number of results you'd get back. I'm not certain that it was the way to do it, but it allowed me to forget that I'm not very good at SQL, I'm terrible at schema design, and even the fact the data is stored in an RDBMS.
This approach also had the advantage of having one place to put the SQL, and prevented users from throwing potentially bad SQL at the database, or asking for people that had a name "GREATERTHAN" 24.
Cheers.
davis
Is this going out live?
No, Homer, very few cartoons are broadcast live - it's a terrible strain on the animator's wrist
| [reply] [d/l] |
Re: OO Application Design
by spartacus9 (Beadle) on Sep 25, 2002 at 04:24 UTC
|
I have always gone with the class method version, i.e., $person->getAdults(); This way seems to require less code upfront. Typically I put all of the class methods that are generic (including the actual DBI connection handle) into a single Package file and use that file from the perl program. That way once you get all your class methods written, you don't have to touch them again while your're messing with the perl program that uses them.
That said, if you have a huge amount of data returned by the calls to your class methods, it may be better to create a separate class that only knows about, in this case, people. That could be used to reduce the amount of data you fetch when you only need a certain small portion of the data. | [reply] |
|
| [reply] |
Re: OO Application Design
by diotalevi (Canon) on Sep 25, 2002 at 04:34 UTC
|
I haven't had the opportunity to work with it yet but I hear Alzabo and Class::DBI go some distance to help you solve some of these problems and keep your hands away from having to write much of the lower-level code that nice OO-persistence can require. My thinking is that Alzabo might do even more for you than other solutions since it will also serve as your schema documentation *and* will generate it as well. Then again - I'm perfectly comfortable doing up a very nice schema in PostgreSQL and don't need Alzabo to create it for me.
Consider those as suggestions. I've got an example of code that does this sort of thing up at jbj-0731.tgz. Browse the Voter::Db classes.
| [reply] |
|
My favorite O/R mapping module is SPOPS by our own lachoy. Have a look.
| [reply] |
Re: OO Application Design
by kabel (Chaplain) on Sep 25, 2002 at 08:26 UTC
|
i think the problem here is that perls array type is so high level that you should really consider if you need an extra "List" container class or just return an array of "person" objects. in a "List" class you could add some extra functionality (whatever that may be), but you got to code it (extra code to maintain) - (i got the feeling that this sounds a bit like how you would do it in java?)
i have experienced that the places where you got to deal with one "object" and with a whole bunch of them is very clearly defined. there is IMO no reason to further generalize the code any more if you are at that stage.
if you have the time you may give the container class approach a try and make the decision for yourself which of the two suits you and the whole project best. just think on a popular perl saying :) | [reply] |
Re: OO Application Design
by abell (Chaplain) on Sep 25, 2002 at 07:56 UTC
|
I believe you should have getAdults as a class method in class Person and let it return an object of type PersonList. A PersonList should just contain the handle of the executed statement (in other words a cursor or ResultSet) and wouldn't hold all elements in memory. It could have methods like get_next, has_more_elements, as_array, letting you either access elements sequentially or get all the bunch as an array.
In a more general setting, a PersonList could be an instance of a superclass DBObjectList, knowing aware of what kind of objects it is retrieving (in your case Person's).
Antonio
| [reply] |
|
I've found this the best way to do it, mostly because it allows lots of generalising and lots of use of polymorphism.
I have objects of class Person, Invoice, Business etc and they all basically want the same methods called on them. Using a class method Person->newIterator actually returns an instance of PersonIterator which is subclassed from DBIterator.
PersonInterator, etc, instances are created on the fly and how they behave depends on the arguments passed by newIterator. Because all the Person, Business, etc classes are all subclassed from the same Entity class, the calling program doesn't actually have to know what class it is dealing with.
So calling:
$any_Iterator = $any_class->newInterator
returns a an instance of something subclassed from DBIterator. Note DBIterator, itself, is abstract.
Then you can keep calling:
$any_Iterator->nextElement;
until it returns undef.
Is this a naughty use of symbolic refs? I don't know. But what I do know is that I find this code easy to maintain easy to extend and easy to tweak.
| [reply] [d/l] [select] |
Re: OO Application Design
by strider corinth (Friar) on Sep 25, 2002 at 21:31 UTC
|
The best way to design, IMHO, is to build your program to follow the pattern set by your data; for example, if your data is a tab-delimited text file in an OO world, an object representing the file would (a lot of the time) be the appropriate translation. If there were to be more than one file, an array of file objects would probably be good (but see below).
Here, it sounds to me like the best thing would be a People object containing references to a bunch of Persons. This model maps well to the data as it touches your program (the database is a single entity) and to the way the human mind works: the database contains information on a bunch of people, not just one, so it's best represented by People, not a Person.
If having Person objects in this interface seems like overkill for your program (though given your description, it doesn't sound to me like it would, unless you're working with a large table) the People object could implement that functionality with subs, like a new_person() function, and maybe find_person().
By the way, I don't advocate always patterning your code after the way your data is presented to it. The fact that you're reading your data from twenty log files doesn't mean you need 20 file objects. If your program is simply parsing the data from the files line by line and file by file, a Logparser object that reads the logs and returns lines on demand would probably be better. If your program is only going to see a slew of lines anyway, it might as well be presented with them in that form.
--
Love justice; desire mercy.
| [reply] |
Re: OO Application Design
by jackdied (Monk) on Sep 26, 2002 at 06:16 UTC
|
Ideally, it depends on how OO you want to be.
A good genalized version would be something like:
Entity (approximately a row in a database)
EntityHTML (HTML display class for Entities)
Person ISA Entity
PersonHTML ISA Person, ISA EntityHTML
In javaspeak, PersonHTML ISA Person, Implements EntityHTML.
Since your talking about RL, Person->new() should take a database ID, or an $Entity::NEWOB (a constant), or be created in Person::new_by_name('bob').
You'll want some way to flush the object back to the database, probably save(). But since (again in RL) you are talking about stuff in a database skip the save() and instead use add() and update() (or your synonyms). Trust me, it saves alot of confusion when reading code versus making save() 'smart'. Low-level things should be dumb, high level things should be smart. Don't forget delete()
A PersonHTML object just knows how to display a person - and nothing about the database - as an HTML form, or as a row on a list. Depending on your data you can throw in EntityPDF or EntityPNG as well. EntityPerl might be a neat one, but you probably just mean serialize().
There is lots of other stuff to think about, Factory classes and such, but tackle those when you need them :)
-jackdied | [reply] |
Re: OO Application Design
by samurai (Monk) on Sep 26, 2002 at 16:11 UTC
|
I usually create a library class for this kind of work. I used to put the code in the object of the kind of data I was pulling, but I figured a library would be more maintainable. For example:
my @users = Project::getUsers();
So that function returns an array of User objects. If you allow your constructor of your User object to take array references as an arg, you can populate the object on the fly with the result row, and then return the list of objects.
--
perl: code of the samurai | [reply] [d/l] |
Re: OO Application Design
by trs80 (Priest) on Sep 26, 2002 at 01:14 UTC
|
What do you want to do with the people in the list? That is how are you going to interact with the ones matching the "adult" criteria? This will/could effect your designed interface to some extent. | [reply] |
Re: OO Application Design
by princepawn (Parson) on Sep 27, 2002 at 01:01 UTC
|
Though the functionality is now within DBI, I still like
DBIx::AnyDBD for creating database driven apps.
You can see an example of code using it in the
PApp::Hinduism distribution.
| [reply] |