我应该将id或实体传递给我的服务

时间:2010-09-24 01:49:00

标签: c#

考虑到我有一项服务来使用界面计算客户帐户余额

public interface ICustomerAccountCalculation
{
    Decimal Balance(int customerId);
}

是否更好的风格,而不是传递客户ID来传递像这样的客户对象

public interface ICustomerAccountCalculation
{
    Decimal Balance(Customer customer);
}

6 个答案:

答案 0 :(得分:4)

我认为这是一个你需要回答的问题,因为它取决于你。传递实体与传递ID的成本与利益是多少?在您的服务合同的情况下,看起来id是足够的信息(我知道我正在做出假设)来获得客户的帐户余额。要考虑的其他一些事项是序列化/反序列化您的实体的成本等等......

但在另一种情况下,根据您正在执行的操作,它可能有意义。假设操作需要来自调用者的关于客户的更多信息,如果已经从调用者中加载了信息,那么去操作中获取该信息是没有意义的...

所以,这取决于。

答案 1 :(得分:2)

仅传递将在函数中使用的值。如果customerid足以让您进行进一步的计算,那么只传递那么多 - 如果需要任何其他字段,则将其作为函数的不同参数传递。

从对象中抽象出函数是一种很好的做法。功能只应与输入VS输出有关。例如,如果您的函数是float computeBalance(float, float),那么它应该能够获取任意两个浮点值并执行计算。传递对象意味着您已经读取了对象并提取了所需的字段......这不是一件好事:)

答案 2 :(得分:1)

如果该功能的目的是计算客户的账户余额,我将假设客户已经创建并包含账户余额。我还假设customerId对每个客户都是唯一的,因此只需使用customerId即可计算(检索)帐户余额。说完这一切之后,如果你需要的只是customerId来创建余额,那么只需传入id即可,但如果你需要客户对象的其他属性,那么传递整个客户可能是个更好的主意或者你可以传递多个参数。

例如,如果您仅基于customerId创建余额,您可以在Balance()方法中执行类似的操作(这看起来更像是检索而不是计算):

decimal balance = from c in Customers
                  where c.CustomerId == customerId
                  select c.Balance;

如上面的linq查询所示,如果您需要的只是customerId,那么请继续并将其传入,但如果您需要其他属性,请传入整个客户或传递更多参数。进一步看,你提到这是为了计算余额,所以这会告诉我你可能需要的不仅仅是customerId,所以在这种情况下传递更多参数或整个对象会更好。

答案 3 :(得分:1)

让我们分解两种实施的责任。

ICustomerAccountCalculation采用ID

  • 按ID检索客户
  • 执行计算

ICustomerAccountCalculation采取客户

  • 执行计算

正如您所看到的,第一个版本不仅仅是执行计算。因此,这违反了单一责任原则。第二个版本应该是您的第一次尝试,并且只有在明确需要时才更改为采用ID的版本。即便如此,如果由于某种原因你需要按ID进行计算,你总是可以从Customer实例中检索它。

答案 4 :(得分:0)

更自然的做法是传递实体,但这通常会导致性能问题,因此在大多数实际情况下,您只需传递密钥。

答案 5 :(得分:0)

今天我正在思考这个问题并考虑以下解决方案。这只是一个想法,但可能有用。

我们的想法是始终拥有实体/对象参数,以统一服务方法。如果调用者没有该对象,它将传递一个只有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,或两者兼而有之)。
  • 服务方法明确地用实体键入,而不仅仅是String或Long标识符。
  • 如果我们以后需要(或不需要)来自实体的更多字段,则易于重构。不必更改来电者代码。

<强>缺点

  • 如果需要更多字段,服务必须调用辅助方法ensureLoaded