我有以下具体的Animal
产品:Dog
和Cat
。
我正在使用parameterized Factory method来创建所述产品。根据传递给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 principle,如果我添加一个新的Animal,我将需要修改Factory方法以反映新的映射。 / p>
有没有办法通过反思让创作更“动态”?更重要的是,我的设计中是否有任何反模式?
答案 0 :(得分:18)
让我稍微回避一下。 SOLID原则很好。但是在某种程度上意识到这些原则已经破裂,甚至是SOLID术语的创始人都承认这一事实。是的,你想要遵循单一责任,开放/关闭等等,但是当你这样做时,某些东西必须知道如何创建所有那些与单一责任完全脱钩的东西。
考虑一下Bob叔叔关于代码中ifs和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。但是必须在某处。关键是减少那些事情和那些事情的数量。
答案 1 :(得分:10)
简单的方法是让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,但不再违反您的开放/关闭原则。
答案 2 :(得分:0)
如果您正在寻找基于反射的方法,您可以执行以下操作......
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;
}
}