jjzjj

c# - 如何在 C# 静态和非静态方法之间做出决定?

coder 2024-05-22 原文

[编辑]

我最初的问题是“为什么要在静态和非静态之间做出决定?两者都做同样的事情......”

不幸的是,它被编辑为我真正想避免的 C# 特定问题。

所以,让我做一些补充:

当我说接口(interface)时,我指的不是 C#-keyword-interface,而是我理解的类似于 C++-interface 的东西:一组定义良好的函数来操作我的对象。
当说削弱我的界面时,我的意思是我有不同的功能(静态/非静态)做同样的事情。当有不同的功能来做同样的事情时,我的界面不再被很好地定义。

所以,正如看门人鲍勃所说,我可以实现一个 Validate() 函数

Document.Validate(myDocumentObject);    

但是也
myConcreteDocumentObject.Validate();

回到我的 Copy()-example 可以实现 Copy() 像
myConcreteDocument.Copy(toPath);

但是也
Document.Copy(myConcreteDocumentObject, toPath)

或者
Document.Copy(fromPath, toPath)

当我想到一个包含属于我的文档的所有文件的文件夹时(在这种情况下,我不依赖于具体实例 - 但我依赖于其他东西:))。

一般来说,我谈论的是静态方法而不是静态类(对不起,如果我忘了提及)。

但正如 Anton Gogolev 所说,我认为我的 Document 类不是一个很好的例子,设计也不是很好,所以我想我必须看看单一职责原则。

我还可以实现某种与我的 DocumentClass 一起运行的 ManagerClass:

例如:
myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);

或者
myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);

但是如果我引用方法 1),我会倾向于创建由自己执行任务的对象,而不是其他对象 (DocumentManager) 对我的 DocumentObject 执行某些操作。

(我希望这不会影响有关 OOP 的宗教讨论;)。

[/编辑]

旧版本:

起初,这似乎是一个非常基本的问题,例如“何时使用静态方法,何时不使用”,但这是我时不时遇到的问题(我很难描述真正的问题是什么;也许只是为了获取为什么(不)使用 1)或为什么(不)使用 2)) 的原因。

(虽然我使用的是 C#-Syntax 这不是 C# 限制的问题)

在 OOP 中有两种处理对象的方法(除其他外):

1)如果我想让我的对象做某事,我只是告诉他这样做:
myConcreteObject.DoSomething();

这就像在和一个对象说话。

2) 或者,如果您喜欢静态方法:
ObjectClass.JustDoIt();

在某种程度上,我认为静态函数只是“感觉”更好。所以我倾向于经常使用静态方法(独立于具体实例 - 独立总是好事)。

因此,在设计类(class)时,我经常必须决定是采用方法 1) 还是方法 2):

想象一下,您有一个“文档”类,它应该代表应该保存到数据库中的文档:

一份文件
  • 由文件系统中的一个或多个图像文件组成(这些成为单个文档页面)
  • 有类似引用书目的东西 - 用户可以添加有关文档的信息的字段 - 保存到一个额外的文件
  • 并且应该有一些操作,如 Copy()、AddPage()、RemovePage() 等。

  • 现在我面临着创建这个类的几种方法:
    //----- 1) non static approach/talking to objects -----
    Document newDocument = new Document();
    
    // Copy document to x (another database, for example)
    newDocument.Copy(toPath);
    

    我喜欢这样:我告诉文档将自己复制到数据库 x 并且对象自己这样做。好的。
    //----- 2) static approach ----------------------------
    Document.Copy(myDocumentObject, toPath);
    

    为什么不?也不错,感觉很方便。。。

    那么,要实现哪一个?两个都?或者将静态方法用于一种辅助类?或者选择方法 1) 并坚持下去不会削弱我的文档类的接口(interface)?

    在考虑这两种方法时,我得出的结论是(理论上)可以将任何函数实现为静态函数:
    Class.Function(aConcreteClassObject, parameters);
    

    但也是非静态的:
    aConcreteObject.DoSomething(parameters);
    

    举一个真实世界的例子:

    [编辑(从路径中添加参数“对不起,我忘了”)]
    //----- 2) static approach ----------------------------
    File.Copy(fromPath, toPath);    // .Net-Framework-like
    

    [/编辑]

    但是也:
    //----- 1) non static approach ------------------------
    ExampeFileClass fileObject = new ExampleFileClass();
    fileObject.Copy(toPath);
    

    甚至(一种面向对象的过度杀伤):
    //----- 1) non static approach, too -------------------
    fileObject.ToPath = @"C:\Test\file.txt";     // property of fileObject
    fileObject.Copy();                           // copy to toPath
    

    那么,为什么(不)使用 1)或为什么(不)使用 2)?

    (我不会过多关注 Document 类示例,因为它更像是一个关于良好类设计的一般性问题。)

    最佳答案

    开始了。

    首先:

    So I tend to use static methods very often (to be independent from a concrete instance - independency is always good thing).



    恰恰相反:使用静态方法时,您非常依赖具体实例。

    至于您的 Document是担心,我不会走任何一条路。您已经列出了 Document 的所有职责类,包括数据聚合、将自身保存到数据库以及页面和复制操作。

    这太多了。每 SRP ,每个“模块”(这里的“模块”用作统称)应该只有一个改变的理由。您的 Document有很多责任,因此它有很多改变的理由。这不好。

    考虑到这一点,我会将所有逻辑移到其他具有严格定义职责的类。我相信,Herb Sutter 或 Andrei Alexandrescu 引入了一个或多或少被接受的标准,如下所示:可以通过对象的公共(public)契约对对象执行的所有操作(思考方法)都应该移到外部有问题的对象。

    关于c# - 如何在 C# 静态和非静态方法之间做出决定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/798036/

    有关c# - 如何在 C# 静态和非静态方法之间做出决定?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    5. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

      我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

    6. Ruby 方法() 方法 - 2

      我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

    7. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    8. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    9. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

      我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

    10. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    随机推荐