in reply to Re^2: OO manner of accessing static variables in a subclass?
in thread OO manner of accessing static variables in a subclass?
Firstly, a few words about some OO relationships. From your usage of terms like "parent", "child" and "subclass", I'm not convinced that you've fully grasped their meanings in the OO context.
This refers to what's called an IS-A relationship. For instance, in English, a Sports Car is a Car.
Equivalently, in Perl, the class SportsCar is a subclass of Car; SportsCar inherits from Car; Car is a parent class of SportsCar; SportsCar is a child class of Car; and @SportsCar::ISA should have Car as one of its elements.
This refers to what's called a HAS-A relationship. For instance, in English, a Car has an Engine; a Car is composed of a number of components one of which is an Engine; a Car is incomplete, and will not function as intended, without an Engine; however, an Engine is not a Car.
Equivalently, in Perl, the class Car needs to load the class Engine to function normally; however, the class Engine is NOT a subclass of Car; Engine DOES NOT inherit from Car; Car is NOT a parent class of Engine; Engine is NOT a child class of Car; and @Engine::ISA should NOT have Car as one of its elements.
This is also a HAS-A relationship but, unlike Composition, it is optional rather than essential. For instance, in English, a Car might have a Radio; a Car can have optional components one of which could be a Radio; a Car is complete, and will function as intended, without a Radio; as with an Engine, a Radio is not a Car.
Equivalently, in Perl, the class Car might conditionally load the class Radio; although, it is not required to function normally; the class Radio is NOT a subclass of Car; Radio DOES NOT inherit from Car; Car is NOT a parent class of Radio; Radio is NOT a child class of Car; and @Radio::ISA should NOT have Car as one of its elements.
Now let's change your original class names to more meaningful ones; perhaps Taxidermist and Taxidermy::Data. It should be fairly obvious that Taxidermy::Data is not a Taxidermist: there's no IS-A relationship here. However, a Taxidermist will have Taxidermy::Data; this is a HAS-A relationship and, as such, there are no parent, child or subclasses involved.
Going back to your original names, and refactoring the code to completely decouple Monks from Monks::Data, here's how you might implement a HAS-A relationship. (Again, the code is simplistic just to show a technique; production code should include validation, error checking and so on.)
In the script (pm_1169455_oo_class_example.pl), I read the name of the data module directly from the command line. This could also be done via options, config files, etc. I've only changed one line:
my $obj = Monks::->new;
to
my $obj = Monks::->new(data => $ARGV[0]);
The module Monks::Data is completely unchanged.
I've created another data module Monks::DataWeird, to test the decoupling, which looks like this:
package Monks::DataWeird; use strict; use warnings; our $VERSION = '20160808.00'; sub get_furries { [qw{Rabbits Alligators Minks}] } sub get_texture_for { +{qw{Rabbits soft Minks supersoft Cats scales}} +} 1;
The Monks module no longer contains any reference to Monks::Data or, indeed, any Monks::* module. It now looks like this:
package Monks; use strict; use warnings; our $VERSION = '0.01'; sub new { my ($class, @args) = @_; my $self = bless { @args } => $class; $self->_init; return $self; } sub _init { my ($self) = @_; eval "require $_[0]->{data}"; } sub _get_data { $_[0]->{data} } sub is_furry { my ($self, $furry) = @_; grep { /$furry/ } @{$self->_get_data->get_furries}; } sub find_fur_texture { my ($self, $fur) = @_; $self->_get_data->get_texture_for->{$fur}; } 1;
Here's three sample runs: two with the real data modules and one with a bogus, non-existent module.
$ pm_1169455_oo_class_example.pl Monks::Data Cats: furry? Yes Alligators: furry? No Rabbits: furry? Yes Fur texture for Cats: coarse
$ pm_1169455_oo_class_example.pl Monks::DataWeird Cats: furry? No Alligators: furry? Yes Rabbits: furry? Yes Fur texture for Cats: scales
$ pm_1169455_oo_class_example.pl XMonks::Data Can't locate object method "get_furries" via package "XMonks::Data" at + Monks.pm line 24.
Just to briefly cover your other points:
"I'm sort of partial to BEGIN blocks, ..."
I have no problem with using BEGIN (or similar) blocks. I didn't use one as I saw no need. See ++hippo's response. Also look at the doco for the our function: it's usage and scoping rules seem to trip up a few users.
"Your guess is correct regarding $self->get_attr vs. $self->{attr}. I personally find the latter a lot easier to use, ..."
See the code for the Monks module. The "latter" form is only used for initialisation (_init()) and the accessor (_get_data()); elsewhere the accessor is used. Do not use the direct access method in other modules or scripts. Although it's usual to bless a hashref for Perl modules, that's not universal by any means: for example, IO::Handle uses a globref and Class::Std uses a scalarref. Even when the object remains a blessed hashref, the accessor could still change: as a contrived example, instead of $self->{attr}, it could become something like $self->{attr}[USER] // $self->{attr}[DEFAULT].
"Sorry about the furry/fluffy thing, I was just trying to have some fun with my sample code. :) "
No need to apologise at all. Changing everything to furry was just expedient for me.
I think my initial comments on "OO relationships", and subsequent refactoring, probably cover your other points.
[Aside: I'm not requesting you make changes, but for future reference take a look at "What shortcuts can I use for linking to other information?" and "Writeup Formatting Tips". Using links (e.g. parent, instead of 'parent') and marking up inline code (e.g. $self->{attr}, instead of $self->{attr}) can improve readability.]
— Ken
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^4: OO manner of accessing static variables in a subclass?
by HipDeep (Acolyte) on Aug 11, 2016 at 05:42 UTC | |
by kcott (Archbishop) on Aug 11, 2016 at 09:35 UTC | |
by HipDeep (Acolyte) on Aug 11, 2016 at 19:11 UTC | |
by Anonymous Monk on Aug 11, 2016 at 10:41 UTC |