Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: Re: Creating Common Constructor

by jmanning2k (Pilgrim)
on Jul 10, 2003 at 17:16 UTC ( [id://273057]=note: print w/replies, xml ) Need Help??


in reply to Re: Creating Common Constructor
in thread Creating Common Constructor

Still some things here that don't make sense from a OO perspective.

Like you said previously, a Zoo has Animals, an Animal is not a Zoo. Therefore, Animals shouldn't really be a subclass of Zoo.

Your implementation still hard codes the animal types into the Zoo class. If you want to add a new type of animal, there are a lot of changes to make.
Instead, the count methods should be members of the Animal subclasses. Zoo should have an array of objects of type Animal, and be able to get the count for each one.

Here's my ideal design:
Zoo.pm - A zoo. This has an array that holds many Animal objects. It knows nothing about specific Animal subclasses. It can also have a factory method that creates a new animal and adds it to the zoo collection.
Animal.pm - These are Animal objects. This is a interface type class that merely defines specific methods that Zoo will use. The factory could also logically be here
Animal::Llama - Subclass of Animal that holds Llamas.
Animal::Camel - Subclass of Animal that holds Camels.


This way, a Zoo has a collection (array) of Animals. To get the counts of each animal type, try this:
my %count; foreach my $animal in (@zooanimals) { # $animal is a Animal object. my $animal_name = $animal->get_name(); $count{$animal_name}++; } # another loop here to print %count.

Get it? The Zoo should hold Animals, and know nothing about subtypes of animals.

Exception: - The factory method can know about animal types. That way it can create the appropriate subclass.
sub add_animal() { my $type = shift; if($type == "Llama") { my $newanimal = new Animal::Llama; } elsif {$type == "Camel") { my $newanimal = new Animal::Camel; } push (@allanimals, $newanimal); } my $zoo = new Zoo; $zoo->add_animal("Llama"); $zoo->add_animal("Llama"); $zoo->add_animal("Camel"); $zoo->count_animals(); __OUTPUT__ There are 2 Llamas in the zoo. There are 1 Camels in the zoo.

This is rough and incomplete. (I would add a Animal::Collection object - a zoo has many collections of animals. A collection is a number of individual animals.) But, this is a better design.
To add a new animal type, you just make two changes - the new class, and add it to the factory method.

Is this clear? I'm happy to clarify if you still need help.

Replies are listed 'Best First'.
Re: Re: Re: Creating Common Constructor
by DeadPoet (Scribe) on Jul 10, 2003 at 18:39 UTC

    jmanning2k, I am interested in your design thoughts, as well may be others, please post additional information. One other aspect that is not illustrated here but will be in my final post is the implementation of persistence by way of Storable.


    Additional Information:

    ** The Zoo object will act as a mapper object to all other created object and will be persistent (Storable) thus maintaining its state (knowledge) of all Animals.

    ** The Animal objects will be persistent thus maintaining their state.

    ** The Zoo object when loaded must be able to re-animate (load) all previously known Animals.

    Questions:

    ** How does this additional information change or affect your design?

    DeadPoet

      Doesn't change much.

      Your Zoo package can have a reanimate method that loads some data from a file or DB. I'll use a flat text file as an example:
      Stored Zoo data: Llama - Feet:4 - Color:Tan Camel - Feet:4 - Humps:2
      The reanimate method will go through this data and do:
      #[pseudocode - will not compile] foreach $line (<FILE>) { # Get $name and hash data from file # $name, $animalstats (hashref) my $newanimal = new Animal($name, $animalstats); push (@allanimals, $newanimal); }
      This repopulates your zoo with the stored information.

      For further enhancement, I'll elaborate on my Animal::Collection idea now.
      Your zoo should really contain several collections of animals. This way all animals of a similar type (or habitat) can be grouped together. This makes it easier to count all the animals in a particular type. I would do this with some sort of hashtable containing arrays of animals. (or animal collection objects).

      To do this, change the @allanimals array to a hashtable. Key it on the animal type (or habitat, etc).
      __DATA__ Llamas: Llama1 - data data data Llama2 - data data data Camels: Camel1 - data data data Camel2 - data data data __CODE__ # [pseudocode] foreach (my $groupname = from_datafile()) { ## Llamas, Camels, the collections. unless (exists $allanimals{$groupname}) ## Create a new collection if you don't already have one for that + animal type. my $newcollection = new Animal::Collection($groupname); $allanimals{$groupname} = $newcollection; } my $collection = $allanimals{$groupname}; # Now work with that collection. Add all your animals in that group. foreach $animal (animals_from_datafile()) { ## llama1, llama2, etc. $collection->add_animal(new Animal($animal, $animalstats); } }
      Aside: I'm assuming Animal->new is a factory method.
      package Animal; sub new ( my $name = shift; my $data = shift; if($name == 'llama') { return new Animal::Llama($data); } elseif ($name == 'camel') { return new Animal::Camel($data); } else { warn "Unknown animal type\n"; return new Animal::Generic($name, $data); } }
      So, you now have an $allanimals hash that holds all your animals. Each Animal type has it's own subtype, and therefore it's own stats, as per your original requirements.
      To work with the animals, you iterate through the collections and animals - use something like:
      foreach $type (keys $allanimals) { my $num_of_animals = $allanimals{$type}->count_collection(); # A met +hod in Animal::Colelction foreach $animal ($allanimals{$type}->get_animals()) { ## Using methods defined by the Animal interface ## But implemented in the Animal::Llama, Animal::Camel, etc subcl +asses. my $name = $animal->get_name(); $animal->feed(); } }
      The important thing to remember here: A zoo can hold any type of animal. You should never mention a specific animal type in your Zoo object. This makes it very difficult to add new animal types later. There are only 3 places where a specific animal is mentioned: in your datafile, in the subclass, and in the factory method.

      ~Jon

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://273057]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-03-28 14:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found