I need to document my design, in particular, the design patterns used, and would like to use the standard terminology.
From Refactoring Guru, "Factory Method defines a method, which should be used for creating objects instead of direct constructor call. Subclasses can override this method to change the class of objects that will be created".
I have a CraneInterface
class with an abstract method, and the signature of this method enforces that its return type is an implementation of an AxisInterface
. Essentially, subclasses of CraneInterface
"override this method to change the class of objects that will be created". The only diference with my version is that it does not necessarily "create" a new instance, it could also return one that already exists. Is this still the Factory Pattern? And if not, does this design pattern have a common name?
i.e: A traditional factory looks like this:
class IAnimal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(IAnimal):
#overide
def speak(self):
print('Woof')
class Cat(IAnimal):
#overide
def speak(self):
print('Meow')
class AnimalFactory(ABC):
@abstractmethod
def make_animal(self) -> IAnimal:
pass
class CatFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Cat()
class DogFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Dog()
My code looks more like this:
class AnimalFactory2(ABC):
@property
@abstractmethod
def animal(self) -> IAnimal:
pass
class CatFactory2(AnimalFactory2):
def __init__(self):
self.__cat = Cat()
#overide
@property
def animal(self) -> IAnimal:
return self.__cat
class DogFactory2(AnimalFactory2):
def __init__(self):
self.__dog = Dog()
#overide
@property
def animal(self) -> IAnimal:
return self.__dog
Does the second example use the Factory Pattern? Does it have a different name or even have a name at all? The main difference is that it does not create a new instance each time it is called.
Extra info:
In my actual code, I have a 3 axis CraneInterface
class that has abstract methods for all the ways you can interact with a crane. It is implemented by a CraneSimulator
and a CraneOpcuaClient
that actually talks to a real crane. The original design of the simulator implemented the abstract method inside the CraneSimulator
class, however, this had lots of duplicated code, as every function of the crane was repeated for each of the 3 axes. To solve this, I created an AxisSimulation
class which had methods to interact with it, and then there are 3 instantiations inside the CraneSimulator
, and the implementations of the CraneInterface
abstract methods simply forward the request to one of the 3 axis objects.
The problem was that the CraneInterface
also needed the ability to notify "observers" whenever the state of the crane changed, for example, a position or temperature change. I.e the CraneInterface
needed to have a function add_on_x_position_changed_callback(self, callback: Callable[[Position],None])
. To do this, the CraneInterface
had properties with custom setters that notified a list of observers whenever the value was set. By putting the AxisSimulation
inside the CraneSimulator
the properties had moved out of the CraneInterface
, and the add_on_changed_callback
methods of the CraneInterface
would no longer work.
So to solve this, the CraneInterface
had an abstract property to return an abstract AxisInterface
class (like the AnimalFactory2
example). The AxisInterface
then had the observable properties with a custom setter (and methods to add observers), so that users of the CraneInterface
can add observers to the data.
I know that the "observable" part is an example of the Observer pattern, but is the deferring of the type of Axis implementation returned, an example of the Factory Pattern?
Thanks.