简体   繁体   中英

Factory Method - Java vs. Python

I have a question regarding the implementation of Factory Method in Java and Python.

Suppose I want to model 2 kind of animals - dogs and cats, and expose a factory method for their creation.

As I understood, the best practice implementation on Java will be:

abstract class Animal{
   public abstract void sound();
}

public class Dog extends Animal{
   public void sound(){
    System.out.println("Woof");
   }
}

public class Cat extends Animal{
   public void sound(){
    System.out.println("Maw");
   }
}

class AnimalFactory {

   //use getShape method to get object of type shape 
   public Animal getAnimal(String animalType){
      if(shapeType == null){
         return null;
      }     
      if(animalType.equalsIgnoreCase("Dog")){
         return new Dog();
      } else if(animalType.equalsIgnoreCase("Cat")){
         return new Cat();
      } 
      return null;
   }
}

However, on Python it will be something like that ( source ):

class Animal(ABC):
   @abstractmethod
   def sound():
        pass

class Dog(Animal):
   def sound():
       print('Woof')

class Cat(Animal):
   def sound():
       print('Maw')

class AnimalFactory():
   @staticmethod
   def getAnimal(typ):
      targetclass = typ.capitalize()
      return globals()[targetclass]()

For my question:

It seems that because I use globals() on Python, I can actually use the AnimalFactory in Python, to create any arbitrary class that within the symbol table on run-time, that accepts zero arguments, in contrast to the Java implementation that checks explicitly the class name.

Is this a bad practice or just a "pythonic way"?

Thanks.

Edit:

I want to clarify why I am not feeling comfortable with the python code:

Suppose I want to write another Factory class for other group of classes, it will have exactly the same implementation as the Animal, and theoretically, I could even use the exact Factory class.

I know I may make some people angry by the following statement, but I feel that the 'duck typing' behaviour, and the lack of formal explicit contract in the code, is the root of the illustrated problem and the Python illnesses in big development projects.

Well, it is not seems a bad practice to me. However, I would first check if such targetClass exists, So I won't get an error.

Plus, I'm sure there are many ways to make the java factory method more efficient. eg I could create from advance a list of all classes that extends Animal , then when i get animalType variable, I could find a class from the list that is corresponding to that type.

There are many ways and libraries that help to get such a list. One popular option is Reflections , which you can use it like that:

Reflections reflections = new Reflections("my.project");
Set<Class<? extends Animal>> classes = reflections.getSubTypesOf(Animal.class);

Then just go over the set and chose the wanted class.

Edit:

As for your edit, well, I wouldn't call it illness. Python capabilities are great, but sometimes there are features of "You can, but it doesn't mean you should" kind, I guess these are one of them. You can define for each factory a collection of "legal classes" you can create in that particular factory - such a practice can lower down a bit your concerns :)

If this is just 'for your own use' then I likely would not be too concerned. However, if it's an interface that 'other people' will use, then in my opinion, something calling itself AnimalFactory has no business returning something that's not an Animal. So, I think a check should be made.

I'd suppose a simple way to do it would be to ensure the result from the globals()[targetclass]() call is an instance of Animal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM