最佳实践:传递对象的方法

5

我有一个简单的问题。

假设我有一个包含大约10个属性的数据对象,并且我想将数据从我的对象传递到一个函数中。 大多数情况下,我只需要在接收函数中使用其中一个值,因此只需传递该值(比如一个int)。那么总是发送整个对象与仅发送其中一个值有何优缺点?

是否有最佳实践?


2
如果你只需要一个属性,为什么要发送一个有10个属性的对象呢? - tbddeveloper
你能否编写一个代码示例,以便我们更好地理解你的问题? - Walter Stabosz
6个回答

13

从性能的角度来看,传递整个对象没有问题。在 C# 中,你只需要传递一个对象的引用,因此不会进行复制。

但是从单元测试的角度来看,请比较以下两种方法:

decimal CalculatePrice(Customer customer);
或者
decimal CalculatePrice(decimal productPrice, int numberOfItems);

第二个原则更易于理解和测试。这个原则被称为迪米特法则

迪米特法则指出,一个对象只应该知道它真正需要的东西。因此,将完整的客户对象传递仅用于访问其Order属性会违反迪米特法则。


如果你把productPrice和numberOfItems放在“Customer”对象里面,我认为这有点混乱。更好的做法(在我看来)是创建一个Order对象,并在其中添加一个CalculatePrice方法。 - Matt Burland
是的 :) 这个例子有些夸张。这就是为什么我说传递完整的客户对象来访问订单(以访问价格和商品数量)。 - Wouter de Kort
这是双刃剑,不过请看我对Robaticus回答的回复。 - Marc Gravell
@MarcGravell 那么你会传递一个区域对象、价格和商品数量吗?或者你会开始使用策略对象?但我的观点仍然是,一个方法应该请求它真正需要的东西。否则你就有了一个虚假的API ;) 很难模拟一个只接收顶层对象以获取对某些低级对象的访问权限的方法。 - Wouter de Kort
@Wouter 无论你如何架构它(策略,等等)- 如果抽象 API 无法预测确切的字段,那么在某个时候,你的代码将需要在更高层次的抽象中调用某些方法,即对象。 - Marc Gravell

11
当你“传递一个对象”时,实际上只是传递了该对象的引用 - 因此在x86上为4个字节,在x64上为8个字节。所以,如果这个方法接收对象感觉自然,那就直接传递对象;那样也可以。任何其他方法可能会更糟糕。
当然,如果感觉这个方法只需要单个int,并且只能永远需要单个int,则传递int也是可以的。
我的观点是:编写支持方法的合理操作方法。

1
抱歉,马克,我非常不同意这个回答。如果你的方法不需要所有其他数据,那么这样做会使代码更难以维护和单元测试。 - Robaticus
你强调这种方法的自然感觉是正确的。在这种情况下,性能考虑除了在极端情况下以外都不会有影响。 - Falanwe
2
@Robaticus,这有着盈亏的循环;你还需要通过API来“定义”逻辑。如果它是一个抽象/接口模式,基础实现可能不知道什么是相关的。以Wouter的例子为例:价格可能会因为客户所处的区域而有所不同。 - Marc Gravell
@Marc - 我同意在单一职责和依赖反转之间保持微妙平衡。但我见过初级开发者这样做是因为他们懒惰而不是出于正确的原因。就像所有事情一样,我建议适度和考虑恰当的实现,而不是使用金钉子寻找一分钱的钉子。你最后的观点总结得很好。谢谢! - Robaticus
@Robaticus 是的,这是一个棘手的问题 - 如果只有“从常识开始,然后添加一些对系统/问题的了解”作为指导,那就太好了;不幸的是,它通常并不奏效。 - Marc Gravell

4

方法是一个专门设计的例程,其存在的目的是执行一项操作。因此,它应该接收提供所需参数的参数,既不多也不少。如果它不是在对象上运作,而是在特定的一组值上操作,则它应该将这些值作为参数输入。如果它操作整个对象,则应该将对象作为参数输入。


1
当你在C#中发送一个对象时,如果它是引用类型,你只传递引用。然而,如果它是值类型(例如int),那么该值将被复制。
因此,如果你想修改包含在对象中的int,仅发送int将导致未修改对象中包含的int。
请考虑这个问题。
public class A
{
    private int foo = 1;

     private void DoStuff()
     {
     staticMethod(foo);
     }
 }

 public static  void staticMethod(int value)
 {
      value += 1;
 }

最后,foo的值仍将为1,而不是2。

1

两者都可以满足不同的用例。

你是否认为如果传递一个对象,整个对象都会被复制?如果是,不是整个对象被复制,只有引用值被复制。


不,这不叫做按引用传递。引用是按值传递的,这是不同的。请阅读http://pobox.com/~skeet/csharp/parameters.html。 - Jon Skeet
只有当传递的对象是一个类时才成立,如果它是一个结构体(例如问题中的整数),它将按值传递。如果 OP 只是在计算中使用该值,那么这不会成为问题,但是如果他想更新它,那么就需要使用 ref 关键字进行传递。 - Trevor Pilley

1

当将一个对象传递给函数时,你只是传递了一个指向该对象的引用,因此这不像是一个繁重的操作。唯一被复制的是一个指针。 如果你传递一个整数,它将会被按值传递,这意味着你将会复制这个整数。

最大的区别要记住的是,当你通过引用传递时,对传入的对象所做的更改将成为该对象的永久更改。如果你按值传递,因为你进行了复制,对该参数所做的任何更改都将丢失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接