首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >工厂和静态方法

工厂和静态方法
EN

Software Engineering用户
提问于 2020-02-13 11:03:51
回答 5查看 1.3K关注 0票数 4

所以我读到的几乎每一篇关于纯粹主义者关于oop的文章,他们总是强调使用静态方法是如何反模式的,并且破坏了代码的可测试性。另一方面,每次我使用工厂(不管编程语言如何)寻找一些示例代码,特别是为了对象构造的目的,我都会在工厂类中看到一个静态方法,返回构造的对象。(以下伪码)

代码语言:javascript
运行
复制
class ProductFactory() {

    public static function make(string name): Product
    {
        if(name contains TV)
            return new TVProduct(name)
        else 
            return new HomeAppliance(name);
    }
}

product = ProductFactory->make('LCD TV');

对我来说,这看起来很好,因为最终我想要一个对象的实例,而不是工厂的实例,如下所示。

代码语言:javascript
运行
复制
productFactory = new ProductFactory();
product = productFactory->make('LCD TV');

我的问题是两方面的。

使用工厂的真正方式是什么?工厂中的静态方法是正确和被接受的使用方法吗?

2-如何为使用静态方法的工厂编写单元测试?

我希望我对使用工厂来构建对象的理解在基本层面上没有缺陷。

EN

回答 5

Software Engineering用户

发布于 2020-02-15 06:18:15

实际上有两种不同的模式,它们的名称中有“工厂”,它们有不同的用途:

  • 工厂方法或静态工厂模式是使用静态方法而不是构造函数来提供更有意义的名称和/或更方便地构造对象的方法。还可以返回不同的子类型(在构造函数中不可能),但是在编译时仍然耦合到所有的子类型。
  • 抽象工厂模式是定义工厂接口的地方,这样您的客户端就可以在编译时与实际实现完全解耦。然后在运行时选择一个工厂实现,客户端可以通过接口创建对象,而无需耦合到任何具体类型。

关于单元测试,静态工厂方法与直接构造函数调用完全相同:它们不能被模拟出来(不诉诸巫毒魔法),但是通常使用它们的类型是您根本不关心的类型,比如值对象。对于任何比这更复杂的东西(特别是那些涉及外部依赖项的),您希望创建一个工厂接口并将其注入客户机(并在单元测试中模拟工厂)。

票数 3
EN

Software Engineering用户

发布于 2020-02-13 11:29:38

在其他“好”代码中有大量静态方法的例子,但是是的,通常使用静态方法被认为是不好的做法。当您在这里讨论时,主要的论点之一是它使测试变得困难。

所以要按反序回答你的问题..。

  1. 如何编写单元测试?

你可以测试工厂本身没有问题,但是你能测试一些使用工厂的东西吗?或者使用工厂内部返回的对象,您想要在其中模拟该对象?

我不会说它不可能,但它不可能没有技巧。

  1. 我的工厂应该使用静态的方法吗?

不是的。静力学可能引起的潜在问题的最简单的解决方法就是不使用静力学。然后,您的代码将从

代码语言:javascript
运行
复制
product = ProductFactory->make('LCD TV');

代码语言:javascript
运行
复制
product = this.injectedIProductFactory->make('LCD TV');

在计划中付出的代价不算太大。

票数 2
EN

Software Engineering用户

发布于 2020-02-14 21:56:44

或者,对于另一个问题中所建议的方法,可能会有一些硬编码但仍然“抽象”的代码:

代码语言:javascript
运行
复制
class ProductFactory() {

    // here factories are injected; could be real
    public ProductFactory(ITVProductFactoru tvProductFactory, IHomeApplianceFactory homeApplianceFactory)
    {
        this->tvProductFactory = tvProductFactory;
        this->homeApplianceFactory = homeApplianceFactory;
    }

    public make(string name): Product
    {
        if(name contains TV)
            return this->tvProductFactory->make(name)
        else 
            return this->homeApplianceFactory->make(name);
    }
}

因此,在组合根中,不需要有选择逻辑,而是将其移到抽象代码中,例如可以进行测试。

票数 2
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/405107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档