C# 我应该将id或实体传递到我的服务中吗
考虑到我有一个计算客户帐户余额的服务C# 我应该将id或实体传递到我的服务中吗,c#,C#,考虑到我有一个计算客户帐户余额的服务 public interface ICustomerAccountCalculation { Decimal Balance(int customerId); } 像这样传递customer对象比传递customer id更好吗 public interface ICustomerAccountCalculation { Decimal Balance(Customer customer); } 更自然的做法是传递实体,但这通常会导致性能
public interface ICustomerAccountCalculation
{
Decimal Balance(int customerId);
}
像这样传递customer对象比传递customer id更好吗
public interface ICustomerAccountCalculation
{
Decimal Balance(Customer customer);
}
更自然的做法是传递实体,但这通常会导致性能问题,因此在大多数实际情况下,只传递键。只传递将在函数中使用的值。如果customerid足以让您执行进一步的计算,那么只传递那么多-如果需要任何其他字段,则将其作为不同的参数传递给函数
从对象中提取函数是一种很好的做法。函数应该只关注输入与输出。例如,如果您的函数是
float computeBalance(float,float)
,那么它应该能够获取任意两个浮点值并执行计算。传递对象意味着您已读取对象并提取所需字段。。。这不是一件好事:)我认为这确实是一个你需要回答的问题,因为这要视情况而定。传递实体与仅仅传递id的成本与收益是什么?就您的服务合同而言,id似乎是获取客户账户余额的足够信息(我知道我正在进行假设)。其他一些需要考虑的事情是序列化/反序列化你的实体的成本等等…
但在另一种情况下,这可能有意义,取决于您正在执行的操作。假设该操作需要调用方提供有关客户的更多信息,如果您已经从调用方中加载了该信息,则转到数据库在操作中获取该信息是没有意义的
所以,这要视情况而定 如果函数的目的是计算客户的帐户余额,我将假设客户已经创建并包含帐户余额。我还将假设customerId对于每个客户都是唯一的,因此只需使用customerId即可计算(检索)帐户余额。话虽如此,如果您只需要customerId来创建余额,那么只需传入id就可以了,但是如果您需要customer对象上的其他属性,那么传入整个customer可能是一个更好的主意,或者您可以传入多个参数 例如,如果仅基于customerId创建余额,则可以在balance()方法中执行类似操作(这看起来更像是一次检索,而不是一次计算):
如上面linq查询中所示,如果您只需要customerId,那么继续并只传入该属性,但是如果您需要其他属性,则传入整个customer或传入更多参数。进一步看,您提到这是为了计算余额,这会告诉我您可能需要的不仅仅是customerId,因此在这种情况下,传递更多参数或整个对象可能会更好。让我们来分解这两种实现的责任 iCustomerAccountId
- 按ID检索客户
- 计算
- 计算
正如您所看到的,第一个版本不仅仅执行计算。因此,这违反了单一责任原则。第二个版本应该是您的第一次尝试,并且只有在明确需要时才更改使用ID的版本。即使如此,如果出于某种原因,您需要按ID进行计算,您始终可以从客户实例中检索它。今天我考虑了这个问题,并想到了以下解决方案。这只是一个想法,但可能有用 其思想是始终具有实体/对象参数,以统一服务方法。如果调用者没有对象,它将传递一个新的“虚拟”对象,只设置ID。该对象被标记为“未加载”,因此您知道只有id可用。如果服务需要对象中的其他字段,它将检查是否已加载,如果未加载,则将从数据库中加载 示例代码:
// caller with the object already loaded
productService.process(product);
// caller without the object loaded
productService.process(new Product(productId));
// service method
void process(Product product) {
// Ensure product is loaded, only if we need more fields.
// We could extract this to a helper method (e.g. ensureLoaded).
if (!product.isLoaded()) {
product = database.getProduct(product.getId());
}
...
}
利与弊我明白了:
专业人士
- 服务方法是统一的(有时不是实体,有时不是id,或者两者都是)
- 服务方法清楚地使用实体类型,而不仅仅是字符串或长标识符
- 如果我们以后需要(或不需要)实体中的更多字段,则易于重构。呼叫方代码不必更改
- 如果需要更多字段,服务必须调用helper方法
李>ensureload
icCustomerAccountCalculation
将检索实体的任务委托给另一个服务,为什么它应该知道客户是通过int
ID检索的?这归结为一个问题
// caller with the object already loaded
productService.process(product);
// caller without the object loaded
productService.process(new Product(productId));
// service method
void process(Product product) {
// Ensure product is loaded, only if we need more fields.
// We could extract this to a helper method (e.g. ensureLoaded).
if (!product.isLoaded()) {
product = database.getProduct(product.getId());
}
...
}