简体   繁体   English

Factory类是否也适用于从数据库中提取数据的功能

[英]Is it appropriate for a Factory class to also include functionality of extracting data from a database

One of the main aspects of software development that I struggle with is delegating the correct responsibility into classes within my program. 我挣扎的软件开发的一个主要方面是将正确的责任委托给我的程序中的类。 Working at my first junior role I'm also being exposed to a lot of different design patterns and ideas, and sometimes the information can be overwhelming. 在我的第一个初级角色工作,我也接触到许多不同的设计模式和想法,有时信息可能是压倒性的。

Obviously when we are building software we tend to state that a class should be responsible for one thing and one thing only. 显然,当我们构建软件时,我们倾向于声明一个类应该只对一件事和一件事负责。 It should do that thing well and nothing more. 它应该做得很好,仅此而已。 So in the case of the Factory pattern the Factory class should be responsible for building the product and exposing an interface that allows the director to extract the product from the factory. 因此,在Factory模式的情况下,Factory类应负责构建产品并公开允许导向器从工厂中提取产品的界面。

However the factory class obviously needs to receive the data to build the product from somewhere, without input data we have no output product. 然而,工厂类显然需要从某个地方接收数据来构建产品,没有输入数据我们没有输出产品。 Therefore I'd like to know whether including functionality for a factory to query a database is appropriate? 因此,我想知道是否包含工厂查询数据库的功能是否合适? My rationale for this is that if the factory is tasked with building a particular product, then it should also be responsible for retrieving the data required to build that product. 我的理由是,如果工厂的任务是构建特定产品,那么它还应负责检索构建该产品所需的数据。 But I'm not 100% sure if this is correct. 但我不能100%确定这是否正确。

Alternatively, should there be a repository class who's responsibility is to retrieve the data in question from the database, which can be then passed to the factory for assembly into the required product? 或者,是否应该有一个存储库类,谁负责从数据库中检索有问题的数据,然后可以将其传递给工厂以组装成所需的产品? The use of a repository class seems a bit excessive in this case as we have a class that will hold a large number of different pieces of data which then must be shipped into the factory class. 在这种情况下,使用存储库类似乎有点过分,因为我们有一个类,它将包含大量不同的数据,然后必须将它们运送到工厂类。

If we also bear in mind Uncle Bob's teachings that state that functions and methods should have absolutely no more than three parameters then we will be breaking this rule by passing in a large amount of data to the factory. 如果我们还要记住鲍勃叔叔的教导,即声明函数和方法绝对不应超过三个参数,那么我们将通过将大量数据传递给工厂来破坏这一规则。 If we first assemble the data into an encompassing class before passing to the factory then we are essentially doing the factory's job within the repository class. 如果我们在传递给工厂之前首先将数据组装成一个包含类,那么我们基本上是在存储库类中完成工厂的工作。

Some guidance would be really appreciated on this, as in my head the lines are very blurry and I'm not sure how I should proceed. 在这方面我会非常感激一些指导,因为我脑子里的线条很模糊,我不知道该怎么办。

You shouldn't use the factory pattern to object building that extracted from a database. 不应将工厂模式用于从数据库中提取的对象构建。 There are the Repository pattern and the Data Mapper pattern for this goal. 此目标有Repository模式Data Mapper模式 Those patterns must encapsulate all logic of work with the data storage. 这些模式必须封装数据存储的所有工作逻辑。 Those patterns must have the following responsibility: 这些模式必须承担以下责任:

  • the Repository must give an interface to business logic for work with data storage 存储库必须提供业务逻辑的接口,以便与数据存储一起工作
  • the Data Mapper must convert data from database to concrete object Data Mapper必须将数据从数据库转换为具体对象

The algorithm of cooperation between objects can look like: 对象之间的协作算法可能如下所示:

  • business logic uses a repository to read/persist objects. 业务逻辑使用存储库来读取/持久化对象。
  • the repository uses a Data Mapper to convert objects to INSERT or UPDATE queries and to convert data from data storage to object 存储库使用Data Mapper将对象转换为INSERT或UPDATE查询,并将数据从数据存储转换为对象

Also, you can read more details about the repository pattern in C# on the site of Microsoft and you can see C# example of the repository pattern 此外,您可以在Microsoft的站点上阅读有关C#中的存储库模式的更多详细信息,您可以看到存储库模式的C#示例

Use 2 different classes. 使用2个不同的类。

A Data Access Object (DAO) provides an abstract interface to the database, and hides its details. 数据访问对象(DAO)为数据库提供抽象接口,并隐藏其详细信息。

A factory abstracts and hides the details of the creation of your objects. 工厂提取并隐藏对象创建的详细信息。 For example, for unit testing you might want to configure the factory so that it doesn't use the Database at all. 例如,对于单元测试,您可能希望配置工厂,使其根本不使用数据库。

To reduce the number of parameters between the DAO and the factory, wrap your many pieces of data in a few logically related classes. 要减少DAO和工厂之间的参数数量,请将您的许多数据包装在几个逻辑相关的类中。

Is it apropriate for a Factory class to also include functionality of extracting data from a database Factory类是否适合包含从数据库中提取数据的功能

My rationale for this is that if the factory is tasked with building a particular product, then it should also be responsible for retrieving the data required to build that product. 我的理由是,如果工厂的任务是构建特定产品,那么它还应负责检索构建该产品所需的数据。 But I'm not 100% sure if this is correct. 但我不能100%确定这是否正确。


A product to retrieve from database is not a trivial object, it is a domain model . 从数据库检索的产品不是一个简单的对象,它是一个域模型 A domain model (aka business model, aka entity(which might indicate a particular instance of it)) belongs to your domain layer (aka business layer). 域模型(也称为业务模型,也就是实体(可能指示它的特定实例))属于您的域层 (也称为业务层)。 In this regard, there are some patterns you should be a minimum familiar with... 在这方面,你应该至少熟悉一些模式......

( Active Record ) VS ( Data Mapper + Repository ) VS ( Table Data Gateway + Factory) 活动记录 )VS( 数据映射器 + 存储库 )VS( 表数据网关 +工厂)

Active record pattern kind of violate the Single Responsibility Principle by leading you to implement database access logic inside your domain model and tightly couples them. 活动记录模式通过引导您在域模型中实现数据库访问逻辑并紧密耦合它们来违反单一责任原则

Ideally, to avoid the cons above for the cost of a slightly increased complexity (on short term only), we separate the database access logic into a supplementary layer, the data access layer . 理想情况下,为避免上述缺点导致复杂性稍微增加(仅在短期内),我们将数据库访问逻辑分离为补充层,即数据访问层 One of the main component of this layer being the data mapper which in our context (READ operation) is in charge to retrieve data from database and map it to a new domain model instance, your specific product (entity). 该层的主要组成部分之一是数据映射器,它在我们的上下文(READ操作)负责从数据库检索数据并将其映射到新的域模型实例,即您的特定产品 (实体)。 More generally it encapsulates CRUD operations to the database abstracting this database. 更一般地,它将CRUD操作封装到抽象此数据库的数据库中。 Its API inputs and outputs are entity objects and possibly Query Objects . 它的API输入和输出是实体对象,可能还有查询对象

Optionally, a featured data mapper would make use of patterns such as: 可选地,特色数据映射器将使用诸如以下的模式:

  • Unit Of Work 工作单位
  • Lazy Loading 延迟加载
  • Identity Map 身份地图
  • Transaction 交易
  • Lock Strategies 锁定策略
  • Metadata Mapping 元数据映射

Alternatively, should there be a repository class who's responsibility is to retrieve the data in question from the database, which can be then passed to the factory for assembly into the required product? 或者,是否应该有一个存储库类,谁负责从数据库中检索有问题的数据,然后可以将其传递给工厂以组装成所需的产品? The use of a repository class seems a bit excessive in this case as we have a class that will hold a large number of different pieces of data which then must be shipped into the factory class. 在这种情况下,使用存储库类似乎有点过分,因为我们有一个类,它将包含大量不同的数据,然后必须将它们运送到工厂类。

Repository is not a part of your data access layer, but of your domain layer. 存储库不是数据访问层的一部分,而是您的域层的一部分。 So it is client of your data access layer. 所以它是您的数据访问层的客户端。 It doesn't encapsulate any database access logic but uses the data mapper. 它不封装任何数据库访问逻辑,但使用数据映射器。

A repository encapsulates query logic for a particular domain model plus a collection of in-memory entities you've previously retrieved. 存储库封装了特定域模型的查询逻辑以及您之前检索的内存中实体的集合。 A very basic example: 一个非常基本的例子:

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);
    }
}

Finally, we can encapsulate database access logic in a table data gateway and use it in a factory. 最后,我们可以将数据库访问逻辑封装在表数据网关中,并在工厂中使用它。 This would result in a solution similar to Gonen I's one . 这将导致类似于Gonen I的解决方案。 It is simple to implement but there might be cons compared to the data mapper solution. 它实现起来很简单,但与数据映射器解决方案相比可能有所不同。 I've never implemented, used or even studied this approach so I can't tell much... 我从来没有实现,使用甚至研究过这种方法,所以我说不出多少......


You'd definitely learn a lot by attempting to implement all that by yourself and I'd encourage you to, but keep in mind that if you need a serious solution, ORMs might be interesting for you. 通过尝试自己实现所有这些,你肯定会学到很多,我鼓励你,但请记住,如果你需要一个认真的解决方案, ORM可能对你有意义。

If you're keen to learn more about all this, I recommend Martin Fowler's Patterns of Enterprise Application Architecture book which is summarized here: https://www.martinfowler.com/eaaCatalog/index.html 如果您希望了解有关这一切的更多信息,请参阅Martin Fowler的企业应用程序架构模式一书,其中总结如下: https//www.martinfowler.com/eaaCatalog/index.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM