My question is OO design. I wrote pseudo code below to illustrate my question. (I say "pseudo-pseudo-code" because it is basically correct, just a few bits of bullshit ...)
I use the Factory pattern to create class objects that match the attributes that pass the Factory::new method. However, there are some attributes that I can only get after creating the object, which I want to use to further subclass or "specialize" the type of object. I want to do this, so I can use the same interface with all the objects in main , independent of the class of the object (I think this is polymorphism ).
Factory class first:
use strict; use warnings; package Vehicle::Factory; sub new { my ( $class, $args ) = @_; if ( $args->{class} =~ /car/i ) { return Vehicle::Car->new($args); } else {
Now for related classes:
package Vehicle; sub new { my ( $class, $args ) = @_; bless $self, $class; $self->color( $args->color ); } sub color { $_[1] ? $_[0]->{_color} = $_[1] : return $_[0]->{_color}; } sub wheels { $_[1] ? $_[0]->{_wheels} = $_[1] : return $_[0]->{_wheels}; } 1;
And subclass:
package Vehicle::Car; use base qw( Vehicle ); sub get_fueltype { my ( $self, $args ) = @_; $self->fueltype = check_fuel_type; } sub fueltype { $_[1] ? $_[0]->{_fueltype} = $_[1] : return $_[0]->{_fueltype}; } 1;
Now for subclasses of "stage 2". I can only create them when I know more about an object that has already been created ...
package Vehicle::Car::Gas; use base qw( Vehicle::Car ); sub fill_her_up {
And the main part of the code:
package main; my $thing = Vehicle::Factory->new( color => "red", wheels => 4 ); $thing->get_fueltype;
(I hope my terribly contrived example makes sense!)
Now I'm not sure ... Should I create a new object using the instance data from $thing ? Is there a way to subclass an object without destroying and re-creating it?
Perhaps I should use the following approach and reuse the Car factory?
package Vehicle::Factory; sub new { my ( $class, $args ) = @_; if ( $args->{class} =~ /car/i ) { return Vehicle::Car->new($args); } if ( $self->fueltype eq "gas" ) { return Vehicle::Car::Gas->new($args); } if ( $self->fueltype eq "diesel" ) { return Vehicle::Car::Diesel->new($args); } if ( $self->fueltype eq "electric" ) { return Vehicle::Car::Electric->new($args); } }
At this point in my real code - unlike my example - there is a lot of instance data to then move on to a new object. I think this can be a little ugly if I have to explicitly pass all the data between old and new objects.
In my real code, there may be hundreds / thousands of such objects that are loaded from the configuration file, and they all require the same treatment, but with some differences in how to do this. This is the difference between using Expect and SSH to receive data from a remote device or using SNMP. The second “level” of information is based on the information that I receive when I request a remote device and get its device type (among other things) ...
End point: I write software almost completely, but there is a very “late” and important requirement that requires such a change. I really want to post late req as simple and elegant as possible. I don’t want to “crack” it and change the interface in main .
Thanks in advance for any pointers.