简体   繁体   English

这是否被视为过程编程(或贫血模式)?

[英]Is this considered as procedural programming (or anemic pattern)?

Let's say there are two classes, one is the user class, which contains the user information;假设有两个类,一个是用户class,包含用户信息; the other one is the payment transaction class. The scenario is simple, if the user's age is > 65, create type A payment transaction;另一个是支付交易class,场景很简单,如果用户年龄>65,创建A类支付交易; otherwise, create type B payment transaction.否则,创建 B 类支付交易。

There are several ways to do this:做这件事有很多种方法:

  1. Create a method not belongs to user nor transaction, just call CreateTransaction.创建一个不属于用户也不属于事务的方法,调用CreateTransaction即可。 The logic is stated in this method:该方法中说明了逻辑:
    func CreateTransaction(user, transaction) {
        if user.GetAge() > 65:
            transaction.CreateA()
        else:
            transaction.CreateB()
    }
  1. The other option is the create a method for the user class:另一个选项是为用户 class 创建一个方法:
     class User {
        ...
        func CreateTransaction(transaction) {
            if user.GetAge() > 65:
                transaction.CreateA()
            else:
                transaction.CreateB()
        }
     }

Then there is a CreateTransactionController method that calls the function like:然后有一个调用 function 的 CreateTransactionController 方法,例如:

func CreateTransactinController(user, transaction) {
    user.CreateTransaction()
}

My question is, is the option 1 considered as procedural programming since the logic is actually not owned by any object?我的问题是,选项 1 是否被视为过程编程,因为逻辑实际上不属于任何 object? (Or anemic pattern?) Is the difference between 1 and 2 be just different place to put the logic? (或贫血模式?)1 和 2 之间的区别是否只是放置逻辑的不同位置?

Thanks!谢谢!

Since you marked this question as DDD, I will answer how a model, driven by the Domain, would implement this.由于您将此问题标记为 DDD,我将回答由域驱动的 model 将如何实现这一点。

The question to answer is whether a Transaction is enclosed within the User object. If it is enclosed, it means that you always go through the user's record to fetch transactions (and never access transactions directly).要回答的问题是一个Transaction是否包含在User object之内。如果包含,则意味着你总是通过用户go的记录来获取交易(并且永远不会直接访问交易)。 If a transaction by itself has a lifecycle, can be accessed directly, controls other parts of the domain, and so on, it cannot be enclosed within a User and is a full-blown aggregate.如果一个事务本身有一个生命周期,可以直接访问,控制域的其他部分,等等,它就不能包含在一个User中,而是一个成熟的聚合。

Enclosing the transaction within the user would mean that the user owns transaction-related operations, so option 2 would be the right way.transaction包含在user中意味着用户拥有与事务相关的操作,因此选项 2 是正确的方法。

If transaction is a different aggregate, you could use a Domain Service (like your option 1), but it is incorrect because you handle two aggregates ( user and transaction ) simultaneously.如果transaction是不同的聚合,您可以使用Domain Service (如您的选项 1),但这是不正确的,因为您同时处理两个聚合( usertransaction )。 You are better off enclosing this functionality within the Transaction aggregate.您最好将此功能包含在Transaction聚合中。

The next question to address is how you would decide the type of transaction.下一个要解决的问题是您将如何决定交易类型。 One way is:一种方法是:

  1. The API request would send the user's age as part of the request API 请求会将用户的年龄作为请求的一部分发送
  2. The controller calls a service and passes the user's age as an integer controller 调用服务并将用户年龄传递为 integer
  3. The service invokes a factory method that accepts age as an integer, initializes, and returns the correct type of transaction.该服务调用一个工厂方法,该方法接受年龄为 integer、初始化并返回正确的交易类型。
  4. The user's age may have changed in the backend by the time the request came through, or the request may have been incorrect.到请求通过时,用户的年龄可能在后端发生了变化,或者请求可能不正确。 You handle this problem by having a "corrective policy," which runs after the payment transaction is created later.您可以通过一个“纠正策略”来处理这个问题,该策略在稍后创建支付交易后运行。 If the user's age matches the type of transaction chosen, then all is good.如果用户的年龄与选择的交易类型相匹配,那么一切都很好。 If it doesn't, the transaction is reversed.如果没有,则交易被撤销。

This is commonly how you handle changes that depend on attributes from multiple aggregates.这通常是您处理依赖于来自多个聚合的属性的更改的方式。 You go ahead and change the state of the aggregate in the system, but check at a later point in time for the related aggregate data, and reverse the change if things are not congruent.你提前go,在系统中修改了聚合的state,但稍后及时查看相关的聚合数据,如果不一致则撤销修改。

A better way is to create a Specification whose explicit task is to derive the right payment type based on the user's age.更好的方法是创建一个Specification ,其明确的任务是根据用户的年龄得出正确的支付类型。 The specification encloses your business logic (> 65), gives context to the age-driven requirement, and acts as a central place where you would control the logic.该规范包含您的业务逻辑(> 65),为年龄驱动的需求提供上下文,并充当您控制逻辑的中心位置。

You can read more about specifications here: https://martinfowler.com/apsupp/spec.pdf您可以在此处阅读有关规格的更多信息: https://martinfowler.com/apsupp/spec.pdf

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

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