I have the following concrete Animal
products: Dog
and Cat
.
I am using a parameterized Factory method to create said products. Depending on the AnimalInfo
parameter that is passed to the Factory method, a concrete product will be created. The mapping logic is placed in the Factory method.
Here is my code:
public abstract class AnimalInfo
{
public abstract String Sound { get; }
}
public class DogInfo : AnimalInfo
{
public override string Sound
{
get { return "Bark"; }
}
}
public class CatInfo : AnimalInfo
{
public override string Sound
{
get { return "Meow"; }
}
}
public abstract class Animal
{
public abstract void Talk();
}
public class Dog : Animal
{
private readonly DogInfo _info;
public Dog(DogInfo aInfo)
{
_info = aInfo;
}
public override void Talk()
{
Console.WriteLine(_info.Sound);
}
}
public class Cat : Animal
{
private readonly CatInfo _info;
public Cat(CatInfo aInfo)
{
_info = aInfo;
}
public override void Talk()
{
Console.WriteLine(_info.Sound);
}
}
Here's my Factory method with its logic:
public static class AnimalFactory
{
public static Animal CreateAnimal(AnimalInfo aInfo)
{
if (aInfo is DogInfo)
return new Dog(aInfo as DogInfo);
if (aInfo is CatInfo)
return new Cat(aInfo as CatInfo);
return null;
}
}
The problem I'm seeing here is that the Factory method itself violates the Open/Closed principle in such a way that if I add a new Animal, I will need to modify the Factory method to reflect the new mapping.
Is there a way to make the creation more "dynamic" via reflection? More importantly, is there any anti-pattern in my design?
For example, the Decorator pattern offers us to follow the Open Close principle. Furthermore, we may use the Factory Method, Strategy pattern and the Observer pattern to design an application with minimum changes in the existing code.
No, it doesn't violate the Open/Closed principle at all. Open/Closed means you can modify the way a system works without modifying the code that already exists.
The Open-Close principle (OCP) is the O in the well known SOLID acronym. A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"; that is, such an entity can allow its behaviour to be extended without modifying its source code.
Let me sidestep a bit. The SOLID principles are good. But realize at some point, the principles break down, a fact even the originator of the SOLID term acknowledges. Yes, you want to follow single responsibility, open/closed, etc., but when you do so, something has to know how to create all those things that are otherwise nicely decoupled with single responsibilities.
Think about one of the things Uncle Bob said regarding ifs and switches in your code. "Have it exactly once." It stands to reason that the long if
or the switch
will indeed be a violation of SRP and OCP. And that's OK, if you have that violation once.
So go ahead, have your
if (a)
return x;
else if (b)
return y;
else if (c)
return z;
else
throw new InvalidOperationException();
And have it once. Yes, it's a violation of OCP. Yes, it might violate SRP. But something somewhere has to. The key is reducing the number of those somethings and those somewheres.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With