I am a C# programmer, and I am looking to make a simple factory. Observe the appempt:
class ShapeFactory:
_registry: Dict[ShapeType, Shape] = {
ShapeType.Shape: lambda: Shape(),
ShapeType.Circle: lambda: Circle(),
ShapeType.Square: lambda: Square()
}
def Create(self, key: ShapeType) -> Shape:
if key in self._registry:
return self._registry.get(key)
raise KeyError(key)
def Register(self, key: ShapeType, value: Shape) -> None:
if key not in self._registry:
self._registry[key] = value
raise KeyError(type)
The issue is that Create
will always return the same instance of, say, Circle
. How can I implement a means to dynamically instantiate an object, while allowing OCP?
Edit: To further extend on my point; in C#, I would declare my dictionary as:
Dictionary<ShapeType, Func<Shape>> _registry = new Dictionary{
[ShapeType.Shape] = () => new Shape(),
[ShapeType.Circle] = () => new Circle(),
[ShapeType.Square] = () => new Square()
}
This will always return a newly instantiated object for each value of the dictionary. This is the effect I wish to reproduce in python.
You've got some larger issues in this design.
First off if you have a mutable attribute in the class, you should define _registry
in the __init__
method of the class (isolated to the instance).
Next, the type attribute to _registry
is wrong. You have a dict
of lambda
, not of Shape
instances. You need Dict[ShapeType, Callable[[], Shape]]
. The Register
method has a similar problem.
You should also follow PEP 8 rules for naming. Try this:
class ShapeFactory:
def __init__(self) -> None:
self._registry: Dict[ShapeType, Callable[[], Shape]] = {
ShapeType.Shape: lambda: Shape(),
ShapeType.Circle: lambda: Circle(),
ShapeType.Square: lambda: Square()
}
def create(self, key: ShapeType) -> Shape:
if key in self._registry:
return self._registry[key]()
else:
raise KeyError(key)
def register(self, key: ShapeType, value: Callable[[], Shape]) -> None:
if key not in self._registry:
self._registry[key] = value
else:
raise KeyError(key)