【问题标题】:Factory design pattern location of switch statementsswitch 语句的工厂设计模式位置
【发布时间】:2014-04-08 21:54:01
【问题描述】:

我正在努力思考工厂设计模式的用处。

与此设计模式的许多实现一样(即http://msdn.microsoft.com/en-us/library/ee817667.aspx),在 Main() 中有一个 switch 语句,它探测一个字符串以决定创建哪个 ConcreteComputerFactory(稍后发送到 ComputerAssembler.Assemble(ComputerFactory factory) 方法)。

我看到问题的方式: 1. 工厂 (Main()) 的用户“知道”根据设计模式的定义应该隐藏的具体工厂实现。 2. 每当引入新的concreteComputerFactory 时,抽象就不成立了!我们必须去客户端 (Main()) 添加另一个 if/case 语句。

主张: 将 if/switch 语句/s 移至 ComputerAssembler。 (这有一个小问题,现在 ComputerAssembler 有 2 个原因需要更改:a. 与创建相关的整体内容 b. 添加新的 ConcreteComputerFactory。但是:这肯定比在客户端(Main)中要好得多)

我假设我还没有完全理解这个想法。我想听听你为什么我指定的问题是不正确的,为什么我的提议不是一个更好的主意

谢谢:)

【问题讨论】:

    标签: oop design-patterns


    【解决方案1】:

    工厂设计模式的好处不是在工厂创建时出现,而是在工厂及其产品被使用时出现。创建工厂的代码知道它正在创建的具体类型。只有在工厂创建之后,当工厂和它的产品通过它们的基本接口而不是它们的具体类型来使用时,你才能看到工厂模式的好处。在基本接口上运行的代码可以在不更改任何代码的情况下创建和使用任意数量的不同具体类。

    例如:

    main()
    {
      // The point isn't to hide concrete types at factory creation time
      Factory* fact = new ConcreteFactoryA();
      f(fact);
    }
    
    void f(Factory* fact)
    {
      // This is where the benefit of the factory pattern is found, 
      // where the factory is *used*, not where it is created
      Product* p = fact.CreateProduct();
      p.DoSomething();
      UseProduct(p);
    }
    

    如果我将 ConcreteFactoryA 替换为 ConcreteFactoryB,则创建工厂的代码必须知道该更改。但我不必以任何方式更改f()。这就是好处所在。一旦我创建了工厂,我的其余代码就可以适应不同的具体类型而无需任何更改。

    【讨论】:

    • 根据您的输入,我得出一个结论:工厂是另一种说法,即“针对接口编程,而不是针对具体实现”。我同意这个想法,因为它可以让我们与具体的实现脱钩。但我们呢?我不这么认为。因为即使有一个(!)单一方法(main())耦合到特定实现也会导致耦合。我宁愿将它移出该类,让另一个类决定使用哪个特定实现(基于它从 main() 获得的一些输入),然后耦合为零。这会更好还是更糟?谢谢
    • 是的,你明白了。工厂模式与简单的“程序到接口”的不同之处在于,它还将许多单独的创建决策(我应该在这里创建哪个具体的 P1?,我应该在那里创建哪个具体的 P2?)预先合并到一个决策(哪个具体我应该创建工厂吗?)。在某个地方,一些代码必须知道它正在创建什么具体工厂,和/或知道如何从任何可用的具体工厂中进行选择。但是,一旦您做出了决定,就不必在每次需要创建新对象时重新探索该决定。
    • 至于与 main() 的解耦,你可以将具体工厂选择和创建的逻辑移动到任何你想要的地方。如果您的语言支持,您还可以使用反射来进一步解耦。我当前的项目正是这样做的——在特定文件夹中查找 DLL,询问每个 DLL 是否具有工厂接口的任何实现。
    【解决方案2】:

    ComputerAssembler 负责组装计算机:) 混合职责总是一个坏主意。通常工厂由几个独立的类共享,例如ComputerAssemblerComputerWarehouse。这就是为什么在一开始就单独选择正确的实现。

    正确的工厂的构建和选择不是这个模式的一部分,它是一个单独的问题。在 Main 中使用 if/else 语句也不好,选择工厂并将其提供给其他对象的逻辑应单独处理。如何?这取决于您的应用程序的逻辑。以下是几个例子:

    1) 每次应用程序启动时都会配置正确的实现,然后您只需在配置文件中设置正确的实现即可。这可以通过Inversion of Control框架来完成,这里是使用Spring的简短示例:

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/my-context.xml");
        ComputerFactory computerFactory = applicationContext.getBean(ComputerFactory.class);
        new ComputerBuilder().build(computerFactory); 
    

    2) 您的应用应该能够在运行时切换工厂。这里的逻辑更复杂,您可以再创建一个负责做出选择的类并将其传递给ComputerBuilder

    【讨论】:

    • 感谢您的评论,但您回答的问题与我所问的问题不同。正如我在问题中所写的那样,我的提议在我已经知道的混合职责方面并不好。但是为什么可以留在客户端(主)中的问题是更有趣的问题。此外,不会有ComputerWarehouse。 ComputerAssembler 的全部意义在于从具体工厂和具体对象中抽象出来,因此无需创建更多它的类型。如果 IoC 容器仍然具有相关性,则需要澄清
    【解决方案3】:

    要选择抽象工厂的实现者,还需要 Selector 类。

    选择器有方法

    Factory select() {
    
    return new ConcreteFactory();
    
    }
    

    客户端(main())会使用这个方法。

    之后。如果您必须选择另一个实现者,您将更改选择方法

    【讨论】:

      猜你喜欢
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 2011-11-20
      • 2010-09-06
      相关资源
      最近更新 更多