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

Ian*_*Ian 12 c# reflection anti-patterns factory-pattern

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

我正在使用参数化的Factory方法来创建所述产品.根据AnimalInfo传递给Factory方法的参数,将创建具体产品.映射逻辑放在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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是我的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里看到的问题是Factory方法本身违反了Open/Closed原则,如果我添加一个新的Animal,我将需要修改Factory方法以反映新的映射.

有没有办法通过反思使创作更"动态"?更重要的是,我的设计中是否有任何反模式?

Ant*_*ram 18

让我稍微回避一下.SOLID原则很好.但是在某种程度上意识到这些原则已经破裂,甚至是SOLID术语的创始人都承认这一事实.是的,你要遵循单一职责,打开/关闭,等等,但是当你这样做,事情已经知道了如何创建所有那些否则很好的去耦单责任的事情.

考虑一下Bob叔叔关于代码中ifs和switch的说法."只有一次." 按理说,长期ifswitch意志确实会违反SRP和OCP.如果你有一次违规行为,那没关系.

所以,继续吧,拥有你的

if (a)
   return x;
else if (b)
   return y;
else if (c)
   return z;
else
   throw new InvalidOperationException();
Run Code Online (Sandbox Code Playgroud)

拥有一次.是的,这违反了OCP.是的,它可能违反了SRP.但某些地方必须这样做.关键是减少那些事情和那些事情的数量.


Jam*_*iec 11

简单的方法是让AnimalInfo自己成为工厂:

public abstract class AnimalInfo<T> where T: Animal
{
    public abstract String Sound { get; }
    public abstract T CreateAnimal();
}
Run Code Online (Sandbox Code Playgroud)

DogInfo的实现:

public class DogInfo : AnimalInfo<Dog>
{
    public override string Sound
    {
        get { return "Bark"; }
    }

    public override Dog CreateAnimal()
    {
        return new Dog(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想要,您可以保留当前的静态工厂:

public static class AnimalFactory
{
    public static Animal CreateAnimal(AnimalInfo aInfo)
    {       
        return aInfo.CreateAnimal();
    }
}
Run Code Online (Sandbox Code Playgroud)

不完全严格遵守工厂模式,IMO,但不再违反您的开/关原则.

  • 答案不错.但是现在考虑你必须从某个地方获取你的DogInfo.例如,与CatInfo相比,什么知道如何创建和返回它?在我看来,这将同样的"问题"推向了另一个地方.最终,*某些东西*必须知道如何为您提供合适的类型.(那可能是配置或代码.但是,*存在*.) (3认同)