考虑到我有一项服务来使用界面计算客户帐户余额
public interface ICustomerAccountCalculation
{
Decimal Balance(int customerId);
}
是否更好的风格,而不是传递客户ID来传递像这样的客户对象
public interface ICustomerAccountCalculation
{
Decimal Balance(Customer customer);
}
答案 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)
让我们分解两种实施的责任。
正如您所看到的,第一个版本不仅仅是执行计算。因此,这违反了单一责任原则。第二个版本应该是您的第一次尝试,并且只有在明确需要时才更改为采用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());
}
...
}
我看到的优点和缺点:
<强>赞成强>
<强>缺点强>
ensureLoaded
。