【问题标题】:C#: Provider vs Factory class exampleC#:提供者与工厂类示例
【发布时间】:2020-10-01 17:33:24
【问题描述】:

我正在使用类 LoggerProvider 来提供 ILogger。对于 ILogger 的每个具体实现,我都使用特定的命名方法。我在想结构,我能说这个provider类是工厂类吗?

public class LoggerProvider
{
    public static ILogger GetDbLogger()
    {
        return new DBLogger();
    }

    public static ILogger GetEmailLogger(string email)
    {
        return new EmailLogger(email);
    }

    public static ILogger GetTxtLogger()
    {
        return new TxtLogger(new BaseTxtLoggerConfiguration(), ProjectManager.GetInstance().GetCurrentProjectSettings());
    }
}

public class CustomerOneService
{
    private readonly ILogger _logger;

    public CustomerOneService()
        : this(LoggerProvider.GetDbLogger())
    { }

    public CustomerOneService(ILogger logger)
    {
        _logger = logger;
    }

    public void Import()
    {
        // some operation with _logger
    }
}
public class CustomerTwoService
{
    private readonly ILogger _logger;

    public CustomerTwoService()
        : this(LoggerProvider.GetTxtLogger())
    { }

    public CustomerTwoService(ILogger logger)
    {
        _logger = logger;
    }

    public void CopyData()
    {
        // some operation with _logger
    }
}

因为如果我正确理解 Factory 的目的,它用于提供特定接口的实例,但在运行时决定将从 Factory 返回哪个具体实现,例如从用户界面输入的一些输入作为参数传递给工厂。但另一方面,另一个目的是提供实例并处理创建对象的问题——当客户端不关心实例是如何创建的时。我的提供者应用了第二个原则,但不是第一个。

我查看了文章Difference between a Factory, Provider and a Service?,但根据工厂和供应商的定义,我仍然不确定哪一个是正确的。

【问题讨论】:

  • 尝试为ImportCopyData 方法编写单元测试。
  • @AlexanderPetrov 我认为这现在会是个问题,但我认为对于这个例子来说没关系,不是吗?我将更新服务中的代码以使其可测试。
  • 您使用的是 .NET Framework 吗?还是核心?
  • @CaseyCrookston .NET 框架

标签: c# design-patterns factory


【解决方案1】:

简而言之,这取决于使用情况。如果 CustomerOneService 和 CustomerTwoService 的多个实例可以共享相同的 Loggers 实例,那么 Provider。 “提供者”意味着您不在乎是否获得新实例或共享实例,只要您获得可以使用的东西即可。

如果 One/TwoService 要求每个实例都获取一个新的记录器实例,那么就是一个工厂。 “工厂”意味着每次调用它的“CreateXYZ”方法之一时,都会得到一个新实例。

如果 One/TwoService 要求每个实例都获得一个记录器的 EXCLUSIVE 实例,那么就是一个池。 “池”意味着每次调用它的一个“GetXYZ”方法时,都会得到一个只有你会使用的实例。然后,当您完成它时“释放”该实例是一个好主意。 “池”并不意味着每次都会是一个新实例。它可以重复使用。但在你发布之前,你会得到它的独占使用权。

Soo.. 你可以说 Factory 是一种 Provider,而 Pool 是一种 Provider。但可以肯定的是,池不是工厂。

Soo#2,你的LoggerProvider 肯定是一个提供者,但从它的实现来看,它也是一个工厂。无论您如何称呼它,都取决于您希望它的用户知道它是一个工厂,并保证始终获得一个新对象。

可能还有其他模式.. 但你可能明白了。它在使用上没有太大区别(嘿,你有一个 X 给你 Ys)。这一切都取决于您管理/分发的资源,并且命名主要是为了暗示您可以从对象源中获得什么行为。

我不知道哪一个最适合您的情况。这取决于您的记录器如何使用以及它们有哪些限制以及您希望花费多少时间来实施和管理,即一个池。通常,工厂/提供者比池简单得多。

此外,由于 One/TwoService 似乎在构造函数中获得了它们的依赖关系,因此请考虑使用 DI/IoCC。而不是通过硬编码的工厂/提供者/等进行静态查找

public CustomerTwoService()
    : this(LoggerProvider.GetTxtLogger())

考虑

public CustomerTwoService(ILogger logger)
    : this(logger)

然后配置 IoC 容器,以便 CustomerTwoService 获得 TxtLogger。

如果没有一个工作的 IoC 容器,那将不会“只是做”,并且第一次将它引入您的项目是另一个单独的主题(但在概念上与您现在正在分析的内容相似,所以它有点在上下文中这个问题),但值得一看,特别是如果您期望有许多组件和/或许多依赖项。

【讨论】:

    【解决方案2】:

    你的LoggerProvider和这个几乎一模一样:

    public enum Scenario
    {
      IWantADbLogger,
      IWantAnEmailLogger,
      IWantATxtLogger
    }
    
    public class LoggerProvider
    {
        public static ILogger GetLogger(Scenario scenario)
        {
            switch(scenario) 
            {
               case Scenario.IWantADbLogger: return new DbLogger();
               //etc etc etc
            }
        }
    }
    

    它看起来更像一个工厂,因为它表明它为您决定返回什么(即使在这种情况下它不使用它,并且实际上与原始的相同)代码)。

    即使是一个运行时余地很小的糟糕工厂,如果它为你生产一些东西,而你没有确切地确定那是什么,我认为你的代码可以做到这一点。您的LoggerProvider 可以连接并返回一个稍微不同构造的 TxtLogger,如果它愿意的话 - 调用者不会知道这一点。只要它为调用者做决定,它就是一个工厂。

    当然供应商也这样做!就像服务一样,基本上所有其他封装的类都这样做。那么有什么区别呢?

    工厂代替了构造器。它们为您创建对象,而不是数据,这些对象属于您,就像它们使用构造函数一样。如果你想保留它,你必须自己存储它,你必须妥善处理它,诸如此类。除非您将其发送到某个地方,否则它不会生活在其他任何地方。

    然后它们通过在运行时在其中保留一些选择元素来(稍微)将自己与构造函数区分开来。选择越多越好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-03
      • 2018-10-20
      • 2013-02-06
      • 1970-01-01
      • 2016-02-18
      • 2015-07-22
      • 1970-01-01
      • 2020-04-07
      相关资源
      最近更新 更多