lundi 23 avril 2018

Is downcasting in this situation acceptable?

I am currently part of a project creating a client-server model to automate a certain task. At a certain point in the project I had to perform downcast to do certain things. Generally, down-casting means your design is flawed. I raised this issue to my lead engineer but she said

It is okay to downcast an interface to its derived class but not an concrete class

I didn't really understand her explanation. Without delving into major details, I will supply a pseudo code describing the actual project scenario. Please note the following is an close enough analogy.

We have a base class UniversalAnimal

class UniversalAnimal{
    private:
        Type type;
        Colour color;
        int weight;
        int legs;
        int wings;
        int fins;
        int fangs;   
        // other common attributes for all animals; getters and setters 
}

So the universal animal class is like a place holder class for any animal. Note, it has fins (fishes), fangs (snakes) and wings (birds).

There is a AnimalFactory class which returns a GenericAnimal interface on the Type. For instance,

GenericAnimal animal = animalFactory.getAnimal(uniAnimal)

After getting a GenericAnimal from the factory; there are certain model specific methods to be called for further processing in the program. In order to call these specific methods, the GenericAnimal animal must be down casted to the corresponding derived class. For example;

class Snake implements GenericAnimal{
    int poisonLevel;
    int fangLength;
    int length;
    bool isPoisonous;

    void setPoisonLevel(int level){
       this->poisonLevel = level;
    }

    int getPoisonLevel const{
       return this->poisonLevel;
    }

    // other getters and setters
    // other methods overriding interface GenericAnimal
}

To set poison level to a snake;

UniversalAnimal uniAnimal = UniversalAnimal();
uniAnimal.setType(Type::SNAKE);
uniAnimal.setColour(Colour::BROWN);
uniAnimal.setFang(2);
uniAnimal.setFins(null);
//irrelevant attributes to snake like wings, fins are set to null by default

GenericAnimal gAnimal = animalFactory.getAnimal(uniAnimal);

if(gAnimal instanceof Snake)
  // checked downcasting
  Snake snake = (Snake) gAnimal;

snake.setPoisonLevel(3);
// call other methods specific to snake
}

Though this is an checked downcasting and will not throw a runtime exception; down-casting is generally means flaws in design. Also if the client who uses the factory needs know the type of the object then, I believe, using factory is a wrong design choice. Please give me insights and possible alternate design (if this design is wrong) for this problem.

Aucun commentaire:

Enregistrer un commentaire