Factory类是否还包含从数据库提取数据的功能是否合适?

时间:2018-11-21 09:27:48

标签: c# design-patterns

我苦苦挣扎的软件开发的主要方面之一就是将正确的职责委派给程序中的类。在我担任第一个初级职位时,我还接触到许多不同的设计模式和想法,有时信息可能会让人不知所措。

很明显,当我们构建软件时,我们倾向于指出一类只负责一件事,而一件事只负责一件事。它应该做的很好,仅此而已。因此,在使用Factory模式的情况下,Factory类应负责构建产品并公开一个接口,该接口允许主管从工厂中提取产品。

但是,工厂类显然需要从某个地方接收数据以构建产品,没有输入数据就没有输出产品。因此,我想知道为工厂查询数据库是否包含功能是否合适?我这样做的理由是,如果工厂的任务是生产特定产品,那么工厂还应负责检索生产该产品所需的数据。但我不确定这是否正确。

或者,是否应该有一个存储库类负责从数据库中检索有问题的数据,然后可以将该数据传递到工厂以组装成所需的产品?在这种情况下,使用存储库类似乎有点多余,因为我们有一个类可以容纳大量不同的数据,然后必须将这些数据传送到工厂类中。

如果我们还牢记鲍勃叔叔的教state,即函数和方法绝对不应包含三个以上的参数,那么我们将通过向工厂传递大量数据来打破此规则。如果我们先将数据组装到一个包围类中,然后再传递给工厂,那么我们实际上是在存储库类中完成工厂的工作。

一些指导对此将是不胜感激的,因为在我的脑海中,线条非常模糊,我不确定应该如何进行。

3 个答案:

答案 0 :(得分:2)

您不应使用工厂模式来构建从数据库中提取的对象。这个目标有the Repository patternthe Data Mapper pattern。这些模式必须封装数据存储的所有工作逻辑。这些模式必须承担以下责任:

  • 存储库必须为业务逻辑提供接口以使用数据存储
  • 数据映射器必须将数据从数据库转换为具体对象

对象之间的协作算法如下:

  • 业务逻辑使用存储库来读取/持久化对象。
  • 存储库使用数据映射器将对象转换为INSERT或UPDATE查询,并将数据从数据存储转换为对象

此外,您可以在the site of Microsoft上阅读有关C#中存储库模式的更多详细信息,并且可以看到C# example of the repository pattern

答案 1 :(得分:1)

使用2个不同的类。

数据访问对象(DAO)为数据库提供抽象接口,并隐藏其详细信息。

工厂将抽象并隐藏创建对象的细节。例如,对于单元测试,您可能需要配置工厂,使其完全不使用数据库。

要减少DAO与工厂之间的参数数量,请将许多数据包装在几个逻辑相关的类中。

答案 2 :(得分:1)

  

Factory类是否还包含从数据库提取数据的功能

     

我这样做的理由是,如果工厂的任务是生产特定产品,那么它也应负责检索生产该产品所需的数据。但我不确定这是否正确。


从数据库中检索的

产品不是一个简单的对象,它是一个domain model。 域模型(又名业务模型,又名实体(可能表示它的特定实例))属于您的domain layer(又名业务层)。 在这方面,您应该至少了解一些模式...

({Active Record)VS(Data Mapper + Repository)VS(Table Data Gateway + Factory)

活动记录模式违反了Single Responsibility Principle,它导致您在域模型内实现数据库访问逻辑并将它们紧密耦合。

理想情况下,为了避免上述缺点(以稍微增加的复杂性为代价)(仅在短期内),我们将数据库访问逻辑分为补充层data access layer。该层的主要组成部分之一是数据映射器,在我们的上下文中(读取操作)负责从数据库中检索数据并将其映射到新的域模型实例,即您的特定 product (实体)。更一般而言,它将CRUD操作封装到数据库中以抽象该数据库。其API输入和输出是实体对象,并且可能是Query Objects

(可选)特色数据映射器将使用以下模式:

  • 工作单位
  • 延迟加载
  • 身份地图
  • 交易
  • 锁定策略
  • 元数据映射
  

或者,是否应该有一个存储库类负责从数据库中检索有问题的数据,然后可以将该数据传递到工厂以组装成所需的产品?在这种情况下,使用存储库类似乎有点多余,因为我们有一个类可以容纳大量不同的数据,然后必须将这些数据传送到工厂类中。

存储库不是数据访问层的一部分,而是域层的一部分。因此它是您的数据访问层的客户端。它不封装任何数据库访问逻辑,但使用数据映射器。

存储库封装了特定域模型的查询逻辑以及您先前检索到的内存中实体的集合。 一个非常基本的例子:

class ProductRepository
{
    private $productCollection;

    public function findById($id)
    {
        if (!$this->productCollection->has($id)) {
            $product = $this->dataMapper->get(new Query(Product::class, $id));
            $this->productCollection->add($product);
            return $product;
        }

        return $this->productCollection->get($id);
    }
}

最后,我们可以将数据库访问逻辑封装在表数据网关中,并在工厂中使用它。这将导致类似于Gonen I's one的解决方案。它实现起来很简单,但与数据映射器解决方案相比可能会有缺点。我从来没有实现,使用或研究过这种方法,所以我不能说太多...


通过尝试自己实现所有这些,您肯定会学到很多东西,我鼓励您这样做,但是请记住,如果您需要认真的解决方案,ORMs对您可能会很有趣。 / p>

如果您想了解更多有关这方面的知识,建议您阅读Martin Fowler的企业应用程序体系结构模式书,该书总结如下:https://www.martinfowler.com/eaaCatalog/index.html