in reply to My first package - need help getting started

This may seem like a red herring, but the first thing that worries me is your choice of name, 'DBParser'. The thing about OO is that it is about objects, so the first question to ask is "what is the object here?". My first guess, looking at the data, is that each record represents a person (or perhaps something more general - an "entity", perhaps), in which case I'd be inclined to call the object "Person" (though I'd probably avoid namespace problems by using a prefix that represented the company name, or perhaps my name or the project name, depending on the scope). An alternative approach, if this record format can be used to describe a variety of things, is to name the class instead after the name of the record format; in that case, it might be worth having subclasses for each of the major different types of thing that the format can represent.

Now, what does the data in a typical file look like: is it multiple records each starting with the 'Key' attribute? If so, I could imagine wanting to write the code like:

use Person; for my $person (Person->parse_from_file('/tmp/somefile')) { next unless $person->surname eq 'Region'; $person->tel('(123) 456-7890'); print $person->text; }

Let me be clear: this is just how I like to write my code, and other people (including yourself) will doubtless have different prejudices. The above code assumes that Person::parse_from_file() knows how to read a sequence of records from a file, turn each one into a "Person" object, and return the resulting list.

It also assumes that these objects are opaque, so that all access is via methods: you can choose to make them transparent hashrefs with documented keys, but then (for example) you always need to do the work to split up the 'Full Name' key so that the 'Surname' key will be there in case someone looks at it, and it probably means you can't allow modification both by way of the 'Surname' field and directly in the 'Full Name' field, because by the time you need to write the record back out you won't know which value is correct.

I tend to like what are sometimes called "polymorphic get/set accessors", which means that you can use the same method either without arguments to fetch the value, or with an argument to set it to a new value. Some others prefer to split such functionality into two methods, eg tel() and set_tel().

I'm sure there are many other aspects worth talking about, but these are just some initial thoughts.

Hugo

Replies are listed 'Best First'.
Re: Re: My first package - need help getting started
by Limbic~Region (Chancellor) on Feb 27, 2003 at 03:43 UTC
    Hugo,
    Thank you for your valuable input.
    I see that my lack of OO understanding has been blatently displayed. I also seemed to have used keywords that were clear to me, but not to everyone. What I am trying to accomplish is the following:

  • Turn a record (bunch of lines) into a complex data structure that can be treated as a single entity.
  • Have the ability to manipulate that complex data structure
  • Access that complex data structure for printing in the same ugly format that I created it with.

    This appears to be what you have gleaned from my poor attempt at explaining this. As far as I am concerned, I do not have a preference on how the code should look as I am completely inexperienced at this. I appreciate the information, but I really do not understand how to code the opaque objects as you suggest. I know that the full key will always be static, even if the broken out pieces change as it will be printed externally. If you could show me some code to illustrate this - I would be very appreciative. If not, what you have already done is appreciated.

    You do not have to use my data to create the opaque object - just show me a template to see the methodology. I am a fairly adept student.

    Cheers - L~R

      Ok, let's assume that the opaque object is implemented internally as a hashref, and that the fullname has a simple format of "surname, initials". Here's a simplistic approach:

      package Person; sub fullname { my $self = shift; if (@_) { $self->{fullname} = shift; } return $self->{fullname}; } sub initials { my $self = shift; if (@_) { $self->fullname(join ', ', $self->surname, shift); } (split $self->fullname, ', ', 2)[1]; } sub surname { my $self = shift; if (@_) { $self->fullname(join ', ', shift, $self->initials); } (split $self->fullname, ', ', 2)[0]; }

      In practice, I'd write it a bit differently: I'd probably have many methods very similar to fullname(), and might well generate them rather than write each one out explicitly. Also, I'd probably cache the derived information like surname and initials, to avoid recalculating them each time, in which case I'd need to be careful to decache that information when the source (fullname in this case) changed.

      I'm surprised that you don't want the module to parse the data for you, since that seems to be a chunk of code that you'd otherwise need to repeat everywhere you deal with these records. But likely I've misunderstood what you're trying to do.

      I guess the most important thing, which I should have said before, is that documentation is the key, particular in perl: the docs for your class will say how you're allowed to use the object, and what you're allowed to assume about it. And in general, anything that the docs don't say you are not allowed to do or assume when using the class or its objects in other code.

      Hugo