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

时间:2010-12-06 14:24:22

标签: 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);
   }
}

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

我希望尽可能保持这些类的抽象。

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

谢谢!

11 个答案:

答案 0 :(得分:28)

取决于:)

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

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

与此同时,“清洁守则”一书也指导我们限制方法参数的数量,最终得出的结论是,没有参数的方法是最佳设计。

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

答案 1 :(得分:14)

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

答案 2 :(得分:7)

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

答案 3 :(得分:6)

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

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

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

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

另一方面,如果你必须为每个复制操作管理状态,例如进度跟踪,错误跟踪,完成回调等,那么在构造函数中传递参数会更有意义,但是还会添加强制执行防止Copy被多次调用。

答案 4 :(得分:4)

老问题但似乎很多人在没有考虑ICopier抽象意图的情况下回答。正如Saurabh所述,使其复制(String,String)(并相应地调整接口)将意味着ICopier的任何其他实现将仅限于使用此方法。

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

ICopier copier = new EmailCopier();
copier.copy(sourceFile, "an@email.com,another@email.com");

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

ICopier copier = new EmailCopier("sourceFile', aListOfEmails);
copier.copy();

总而言之,如果接口的实现具有很大不同的参数,则应该使用带有简单命令的构造函数参数。如果所有实现都在相同的输入上运行,那么方法参数就可以了。

答案 5 :(得分:4)

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

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

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

答案 6 :(得分:1)

一切都与使用有关;

哪一个更容易?

FileCopier f = new FileCopier(sourceFrom,sourceTo);
f.Copy();

FileCopier f = new FileCopier();
f.Copy(sourceFrom,sourceTo);

我更喜欢第二种,不仅因为它更容易阅读,而且,一旦路径发生变化,您就不必重新创建对象。在ctor中设置源代码不是一个好主意。但同样,它可能只是我。

答案 7 :(得分:1)

除非有许多其他方法对您未向我们展示的源文件和目标文件进行操作,否则FileCopier应该是static class,而不是将文件路径存储为类 - 水平变量。相反,类的所有单个方法都应该接受要操作的文件(以及任何其他必要的信息或设置)作为参数。这样,每次要复制文件时,都不必实例化该类的实例。

FileCopier fc = new FileCopier(src, dest);
fc.Copy();

FileCopier.Copy(src, dest);

我在这里谈论的最好的例子是.NET Framework中的System.Math classSystem.IO.File class也以这种方式工作(并提出了为什么要重新创建它的问题。)

答案 8 :(得分:1)

我更喜欢构造函数接受参数,因为FileCopier的责任是将文件从源复制到目标,并且它实现的接口可以与其他异构类一起使用,所以如果你将参数提供给Copy()函数,它将变得更具体,但在当前状态下,它可以在许多需要复制功能的地方使用

答案 9 :(得分:1)

如果您的类中只有一个复制方法,那么最好将参数传递给方法。但是,如果必须使用同一个对象执行多个操作,则将它们传递给构造函数会很有帮助。

例如:

    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);
       }

       public void DeleteSource()
       {
       }

       public void DeleteCestination()
       {
       }

  etc...
    }

答案 10 :(得分:1)

奇怪的是,没有人提及您的界面ICopier

只要看一下这个界面,我就会传递方法本身的参数。 因为,它是一个契约,它也应该强制实现这个接口的对象接受完成/实现任务的合法参数。

如果ICopier要求实施Copy(),它还应提供完成任务所需的值/参数。