What is the correct pattern for handling a subclass using a type?

I have a collection of Animal objects.

My main code wants it all to be treated as Animals, anyway. Each animal needs to be processed in some way. The nature of the treatment depends on the subtype of the animal (bird, mammal, etc.).

My code is as follows.

public interface Animal {
    public String getTaxonomyClass(); 
}

public abstract class Bird implements Animal {

    @Override
    public String getTaxonomyClass() {
        return "aves";
    }

    // Specific to birds
    public abstract float getWingspan();

}

public abstract class Mammal implements Animal {

    @Override
    public String getTaxonomyClass() {
        return "mammalia";
    }

    // Specific to mammals
    public abstract int getToothCount();

}

public interface AnimalProcessor {
    public String getSupportedTaxonomyClass();
    public void process(Animal a);
}

public class MammalProcessor implements AnimalProcessor {

    @Override
    public String getSupportedTaxonomyClass() {
        return "mammalia";
    }

    @Override
    public void process(Animal a) {
        System.out.println("Tooth count is " + ((Mammal)a).getToothCount());
    }

}

public class BirdProcessor implements AnimalProcessor {

    @Override
    public String getSupportedTaxonomyClass() {
        return "aves";
    }

    @Override
    public void process(Animal a) {
        System.out.print("Wingspan is " + ((Bird)a).getWingspan());
    }

}

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ZooKeeper {

    Map<String, AnimalProcessor> registry = new HashMap<String, AnimalProcessor>();

    public void registerProcessor(AnimalProcessor ap)
    {
        registry.put(ap.getSupportedTaxonomyClass(), ap);
    }

    public void processNewAnimals(List<Animal> newcomers)
    {
        for(Animal critter : newcomers)
        {
            String taxonomy = critter.getTaxonomyClass();
            if(registry.containsKey(taxonomy))
            {
                // if I can process the animal, I will
                AnimalProcessor ap = registry.get(taxonomy);
                ap.process(critter);
            }

        }
    }
}

import java.util.LinkedList;
import java.util.List;

public class MainClass {

    public static void main(String[] args) {

        ZooKeeper keeper = new ZooKeeper();
        keeper.registerProcessor(new MammalProcessor());
        keeper.registerProcessor(new BirdProcessor());

        List<Animal> animals = new LinkedList<Animal>();

        animals.add(new Mammal() {  // badger

            @Override
            public int getToothCount() {
                return 40;
            } } 
        );

        animals.add(new Bird() {  // condor

            @Override
            public float getWingspan() {
                return 2.9f;
            } }
        );

        keeper.processNewAnimals(animals);

    }
}

This is usually easy to understand and works great! I can add plugins for new processors and animal types at my leisure without changing the ZooKeeper class or any of the interfaces. You can imagine a more advanced main class by loading Animals from the database and processing them one at a time.

, AnimalProcessor! , , . , Bird mammalProcessor process(), ClassCastException.

- , ? , , ! (ZooKeeper) , , ​​. !

+3
6

:

public interface Animal {
    public AnimalProcessor<? extends Animal> getProcessor();
}

.

public interface AnimalProcessor<T extends Animal> {
     public void process(T a);
}

, . :

public abstract class Bird implements Animal {
    private BirdProcessor processor = new BirdProcessor();
    public abstract float getWingspan();
    @Override
    public AnimalProcessor<Bird> getProcessor() {
        return processor; 
    }
}

public class BirdProcessor implements AnimalProcessor<Bird> {
    @Override
    public void process(Bird b) {
        System.out.print("Wingspan is " + b.getWingspan());
    }
}
+1

:

public interface Animal {
    public String getTaxonomyClass(); 
    public void process();
}

, Animal, . :

public class Bird implements Animal {

    public Bird(float wingSpan) {
        this.wingSpan = wingSpan;
    }

    @Override
    public String getTaxonomyClass() {
        return "aves";
    }

    @Override
    public void process() {
         System.out.print("Wingspan is " + wingSpan);
    }

    // Specific to birds
    private float wingspan;
}

AnimalProcessor, :

 public void process(Animal a) {
      a.process();
 }
+1

generics .

-, Generic AnimalProcessor:

public interface AnimalProcessor <T extends Animal> {
    public String getSupportedTaxonomyClass();
    public void process(T a);
}

, - , :

public class MammalProcessor implements AnimalProcessor<Mammal> {

    public String getSupportedTaxonomyClass() {
        return "mammalia";
    }

    public void process(Mammal a) {
        System.out.println("Tooth count is " + a.getToothCount());
    }

}

, .

+1

AnimalProcessor generic;

public interface AnimalProcessor<T extends Animal> {
    public String getSupportedTaxonomyClass();
    public void process(T a);
}

public class MammalProcessor implements AnimalProcessor<Mammal> {

    @Override
    public String getSupportedTaxonomyClass() {
        return "mammalia";
    }

    @Override
    public void process(Mammal a) {
        System.out.println("Tooth count is " + a.getToothCount());
    }

}
+1

, ...

public abstract class Bird implements Animal {

    @Override
    public String getTaxonomyClass() {
        return "aves";
    }

    // Specific to birds
    public abstract float getWingspan();

}

Birds , 0. , - ...

public class Bird implements Animal {

    float wingspan = 0.0f;

    public Bird(float wingspan){
        this.wingspan = wingspan;
    }

    @Override
    public String getTaxonomyClass() {
        return "aves";
    }

    // Specific to birds
    public float getWingspan(){
        return wingspan;
    }

}

, Bird, ...

    animals.add(new Bird() {  // condor

        @Override
        public float getWingspan() {
            return 2.9f;
        } }
    );

...

animals.add(new Bird(2.9f)); // condor

, . Mammal.

... Animals , process() Bird, BirdProcessor. Animal public void process();. Bird :

public void process() {
     System.out.print("Wingspan is " + getWingspan());
}

AnimalProcessor, ( : )...

public class AnimalProcessor {
    public void process(Animal a) {
        a.process();
    }
}

AnimalProcessor Animals.

, AnimalProcessor , , , , ClassCastException ( BirdProcessor)...

public void process(Animal a) {
    if (a instanceof Bird){
        System.out.print("Wingspan is " + ((Bird)a).getWingspan());
    }
}

, ?

0

,

   public abstract int getToothCount();

... Animal. Animal. , , .

, Animal.

getToothCount() "0".

getWingspan(), getTootCount() .., . , "boolean hasWings()", "boolean hasTeeth()" .. .. Animal.

, - a:

if (a.hasWings()) System.out.println("My wingspan is "+a.getWingSpan());

. , Animal .

Animal. . , getWingSpan() 0, getToothCount() 0 .. Shark getToothCount(). Eagle getWingSpan()...

( ) , .

0

All Articles