满足开/闭原则的工厂模式
本文关键字:工厂 模式 原则 满足 | 更新日期: 2023-09-27 18:12:18
我有以下具体的Animal
产品:Dog
和Cat
。
我使用一个参数化的Factory方法来创建上述产品。根据传递给Factory方法的AnimalInfo
参数,将创建一个具体的产品。映射逻辑放在Factory方法中。
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);
}
}
下面是我的Factory方法和它的逻辑:
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;
}
}
我在这里看到的问题是,Factory方法本身违反了Open/Closed原则,如果我添加一个新的Animal,我将需要修改Factory方法以反映新的映射。
是否有一种方法,使创建更"动态"通过反射?更重要的是,我的设计中是否存在反模式?
让我稍微回避一下。SOLID原则是好的。但要意识到,在某些时候,这些原则会崩溃,即使是SOLID术语的创始人也承认这一事实。是的,您希望遵循单一职责,打开/关闭等,但是当您这样做时,某些必须知道如何创建所有这些东西,否则它们将与单一职责很好地解耦。
想想Bob大叔说过的关于代码中的if和switch的一件事。"只吃一次。"很显然,长if
或switch
确实违反了SRP和OCP。这没关系,如果违反了一次
继续,输入
if (a)
return x;
else if (b)
return y;
else if (c)
return z;
else
throw new InvalidOperationException();
和它一次。是的,这违反了OCP。是的,它可能违反SRP。但是某个地方必须。关键是减少那些东西和那些地方的数量。
简单的方法就是让AnimalInfo
本身成为工厂:
public abstract class AnimalInfo<T> where T: Animal
{
public abstract String Sound { get; }
public abstract T CreateAnimal();
}
DogInfo的实现:
public class DogInfo : AnimalInfo<Dog>
{
public override string Sound
{
get { return "Bark"; }
}
public override Dog CreateAnimal()
{
return new Dog(this);
}
}
如果你想,你可以保留当前的静态工厂:
public static class AnimalFactory
{
public static Animal CreateAnimal(AnimalInfo aInfo)
{
return aInfo.CreateAnimal();
}
}
不完全严格遵守工厂模式,IMO,但不再违反你的开/关原则。
如果您正在寻找基于反射的方法,您可以做如下操作…
public static class AnimalFactory
{
public static Animal CreateAnimal(Type animalType)
{
return Activator.CreateInstance(animalType) as Animal;
}
public static Animal CreateAnimal(string animalType)
{
Type type = Assembly.GetExecutingAssembly().GetType(animalType);
return Activator.CreateInstance(type) as Animal;
}
}