【问题标题】:How to do this without using an IF condition如何在不使用 IF 条件的情况下执行此操作
【发布时间】:2012-09-26 11:23:09
【问题描述】:

我有一个定义一种方法的接口。该接口有多个以不同方式实现该接口的类。

例如:

interface IJob {
  void DoSomething();
}

class SomeJob : IJob{
  public void DoSomething() {
    // Do something ...
  }
}

class AnotherJob : IJob {
  public void DoSomething() {
    // Do something ...
  }
}

...

我的工厂类会有一堆这样的 IF 语句

if (some condition)
{
   IJob job = new SomeJob (); 
else
{
   IJob job = new AnotherJob (); 
}

有没有办法避免每次出现新情况时都修改工厂类。这不能仅仅通过添加一个实现 IJob 的新类来完成吗?

编辑: [我想弄清楚Antiifcampaign 的这些人在做什么]

感谢您的宝贵时间...

【问题讨论】:

  • 如果你不想if条件编译器如何理解你想要执行的女巫代码块。?
  • 程序运行时条件可以改变吗?
  • 对象应该分配到某个地方。
  • @AntonSizikov:是的,条件将取决于用户输入。
  • @KarelFrajtak:但需要有一些条件,基于这些条件我将正确的对象发送到期望它的类..对吗?..你有任何代码示例吗?

标签: c# oop object-oriented-analysis


【解决方案1】:

您必须以某种方式将条件和决定联系起来。

Dictionary<int, Action<IJob>> _methods = new ...

填写字典:

_methods.Add(0, () => {return new SomeJob();});
_methods.Add(1, () => {return new AnotherJob();});

然后使用它:

public IJob FactoryMethod(int condition)
{
   if(_methods.ContainsKey(condition))
   {
      return _methods[int]();
   }
   return DefaultJob; //or null
}

您需要在应用程序启动时填写字典。从配置文件或其他代码。 因此,当您有新的条件时,您无需更改工厂。 你喜欢这个变种吗?

【讨论】:

  • 我建议使用与 int 不同的类型(可能是枚举?)以使意图更具可读性和明显性(1 在这里表示什么 var job = JobFactory.GetJob(1) ?)var job = JobFactory.GetJob(Requirement.CleanUp) 更好地传达了意图
  • 当然,int 就是一个例子。字典的 _methods 名称也是一个例子。 FactoryMethod 是一个坏名字:) 无论如何都是好建议。谢谢
【解决方案2】:

必须在某个地方决定要创建什么,而且很可能总是涉及某种条件语句。

但是,如果您可以安排事情以遵循合理的命名约定和/或添加反射支持(如属性),则可以通过使用反射来减少修改工厂类的需要。

有关如何在 .Net 中执行此操作的一些想法,请参阅 this article

您还可以根据字符串到类名的映射做出决定,或者甚至像另一个很好的方法答案一样,在应用程序启动时加载,并在运行时通过反射创建类。必须有一些东西来提供地图,但您也许可以将大部分决定转移到配置上。

【讨论】:

  • 感谢您的链接。我会看看。加载所有类不会影响实时应用程序的性能?
  • 您可能会“即时”加载类。即,当调用工厂方法时,工厂仍然使用反射。
【解决方案3】:

这取决于您的域的动态。如果您需要经常评估条件,您可以为IJob 的每个实现设置某种工厂,例如SomeJobFactoryAnotherJobFactory,...

每个都有方法MeetsCondition,如果满足条件,该方法将评估为真,然后返回新实例。

public class SomeJobFactory : Factory<IJob>
{
   public bool MeetsCondition() { ... }

   public IJob CreateInstance() { return new SomeJob(); }
}

在你的代码中

foreach(var jobFactory in allJobFactories)
{
   if(jobFactory.MeetsCondition())
   {
      return jobFactory.CreateInstance();
   }
}

您还使用 IoC 来获取所有工作工厂:

allJobFactories = IoC.ResolveAll<Factory<IJob>>();

当您添加新的作业工厂时,您不必在此示例中修改一行代码。

如果您的代码更加静态,您可以使用 DI 和 IoC,在启动时创建一次对象。

【讨论】:

    【解决方案4】:

    我不喜欢你,但你总是可以使用泛型:

    public IJob GetJob<T>() where : IJob ,new()
    {
        IJob job = new T(); 
        return job;
    
    }
    

    【讨论】:

    • 这无济于事,因为调用者需要知道实现类型(它会像这样var job = Factory.GetJob&lt;SomeJob&gt;() 调用)那么工厂给你带来了什么好处?
    猜你喜欢
    • 2020-03-13
    • 2020-04-10
    • 2015-02-12
    • 2013-07-11
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 2023-03-31
    • 2013-10-04
    相关资源
    最近更新 更多