构造函数参数与方法参数?

ada*_*iko 29 c#

一个非常简单的问题,我希望得到一个"情况决定"的答案.我想知道人们对将参数传递给构造函数或方法的想法.

我会尝试为我的问题设置一个上下文:

public interface ICopier
{
   void Copy();
}

public class FileCopier : ICopier
{
   String m_source;
   String m_destiniation;

   FileCopier(String source_, String destination_)
   {
        m_source = source_;
        m_destiniation = destiniation_;
   }

   public void Copy()
   {
        File.Copy(m_source, m_destiniation, true);
   }
}
Run Code Online (Sandbox Code Playgroud)

或者FileCopier.Copy()是否应该接受source_和destination_作为方法参数?

我想让这些类尽可能抽象.

我问这个问题,因为我现在有其他接口/类用于删除,重命名等等,我想为此创建一个标准.

谢谢!

Mar*_*ann 28

这取决于 :)

基本上,面向对象表明对象应该封装数据和行为.将数据作为构造函数参数传递时,表明这是要封装的数据.

另一方面,当您将数据作为参数传递时,您指示这是以某种方式较少耦合到对象的数据.一旦开始转向数据上下文交互(DCI),许多对象越来越倾向于封装行为而不是数据.

与此同时,"清洁代码"一书也指导我们限制方法参数的数量,最终得出的结论是,没有参数的方法是最佳设计.

因此,我倾向于通过将其作为构造函数参数传递来封装数据,以便拥有简单的API.然后它看起来很像Command对象.

  • +1表示代码完成。 (2认同)
  • 我完全同意Mark的观点,但了解上下文很重要。我们不能将每个应用程序设计成最终的结论,即理想的类将看起来像“ interface IFoo(){void Foo()}”。我认为好像在使用DI一样有用。您的依赖项是什么(可注入项/构造函数参数),运行时值是什么(可更新项/方法参数)。在需要将单个源文件复制到dest文件的类的上下文中,希望清楚地表明“ interface ICopier {void Copy(src,dest);}”比“ interface ICopier {void Copy();}”更有意义。 ... 对?:) (2认同)

Red*_*ter 15

将它们传递给方法.这样,您可以复制到多个位置而无需重新实例化FileCopier,并执行可能需要其他参数的其他操作.在这种情况下,您可以将方法设置为静态,因此根本不需要实例化.例如,您会注意到这是C#File类的工作方式.

  • 我已经采用了这种方法.我决定将source_和destination_作为方法参数传递,因为这两位数据仅对副本有意义,而不是之后.我将使用构造函数参数来处理状态数据,例如'overwrite'标志,因为这将适用于Copy()的许多执行. (2认同)

t3m*_*jin 9

它还取决于应用程序是无效的还是有状态的.在有状态架构上,我可能会选择在构造函数上传递参数,允许我保存该对象并多次调用已初始化的实例.在无状态应用程序中,每次创建对象实例时都必须创建对象的状态,这有点多余,所以我选择在方法上传递这些参数以获得更清晰的界面.


Ran*_*Ran 6

一般来说,最好避免在课堂上添加不必要的状态.这意味着,如果某些数据项仅在特定操作的上下文中需要,您通常更愿意将它们仅作为方法中的局部变量,并将它们作为参数传递.

这样,您的代码也往往不易出错,因为方法之间共享的不必要状态会更少,因此错误的可能性更小.

如果要强制在使用类期间值永远不会更改,则应将参数传递给构造函数.

创建一个只能复制特定文件的FileCopier对象可能没有意义,因此在您的情况下,方法更合适.

另一方面,如果您必须为每个复制操作管理状态,例如进度跟踪,错误跟踪,完成回调等,那么在构造函数中传递参数会更有意义,但也会增加强制执行以防止Copy被执行不止一次打电话.


rem*_*rel 6

我最近发现了以下规则“如果因为实现而使用参数则将其放入构造函数中,如果由于接口使用参数则将其放入方法中”。

问题是您在 Copy 方法上方没有任何评论:

  • 如果它是“将一个文件从目标复制到源”,那么您应该添加源和目标参数,因为您在接口描述中谈到它
  • 如果它是“当覆盖复制某些东西时”,则将其添加到构造函数中,因为只有您的 FileCopier 实现需要它


mmm*_*reg 5

这是一个古老的问题,但似乎很多人在回答时都没有考虑ICopier抽象的意图。正如Saurabh所述,使其成为copy(String,String)(并相应地调整接口)将意味着ICopier的任何其他实现都将限于使用此方法。

如果您需要扩展它以创建一个EmailCopier来将文件从源发送到电子邮件列表而不是目标文件,该怎么办?您可以编写一个继续接受(字符串,字符串)的hacky方法:

ICopier copier = new EmailCopier();
copier.copy(sourceFile, "an@email.com,another@email.com");
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用适当的数据结构和简单的copy()命令将所有这些信息放入构造函数中:

ICopier copier = new EmailCopier("sourceFile', aListOfEmails);
copier.copy();
Run Code Online (Sandbox Code Playgroud)

总而言之,如果接口的实现具有很大不同的参数,则应通过简单的命令使用构造函数参数。如果所有实现都在相同的输入上运行,则方法参数很好。