满足开/闭原则的工厂模式

本文关键字:工厂 模式 原则 满足 | 更新日期: 2023-09-27 18:12:18

我有以下具体的Animal产品:DogCat

我使用一个参数化的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的一件事。"只吃一次。"很显然,长ifswitch确实违反了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;
    }

}