[英]How to decide between C# static and non-static methods?
[Edit] [编辑]
My original-question was "Why to decide between static and non-static? Both do the same..." 我的原始问题是“为什么要在静态和非静态之间做出决定?两者都是一样的......”
Unfortunately it was edited to a C#-specific question what I really wanted to avoid. 不幸的是,它被编辑成一个C#特定的问题,我真的想避免。
So, let me do some additions: 所以,让我做一些补充:
When I say interface, I don't mean the C#-keyword-interface but what I understand something like a C++-interface: A set of well defined functions to operate with my object. 当我说接口时,我不是指C#-keyword接口,而是我理解的东西,比如C ++接口:一组定义良好的函数来操作我的对象。 When saying weaken my interface, I mean I have different functions (static/non-static) that do the same thing.
当说削弱我的界面时,我的意思是我有不同的功能(静态/非静态)做同样的事情。 My interface is not well defined anymore when there are different functions to do the same thing.
当有不同的功能来做同样的事情时,我的界面不再被很好地定义。
So, as Bob the Janitor posted, I can implement a Validate()-function 所以,正如看门人Bob发布的那样,我可以实现一个Validate()函数
Document.Validate(myDocumentObject);
but also 但是也
myConcreteDocumentObject.Validate();
To get back to my Copy()-example one could implement Copy() like 要返回我的Copy() - 示例可以实现Copy()之类的
myConcreteDocument.Copy(toPath);
but also 但是也
Document.Copy(myConcreteDocumentObject, toPath)
or 要么
Document.Copy(fromPath, toPath)
when I think of a folder that contains all the files belonging to my Document (in this case I'm not dependent of a concrete instance - but I'm dependent from other things :)). 当我想到一个文件夹,其中包含属于我的Document的所有文件(在这种情况下,我不依赖于具体的实例 - 但我依赖于其他东西:))。
In general I'm talking about static methods not static classes (sorry, if I forgot to mension). 一般来说,我说的是静态方法,而不是静态类(对不起,如果我忘了推荐)。
But as Anton Gogolev said I think my Document class is not a good example and not well designed so I think I will have to have a look at the Single Responsibility Principle. 但正如Anton Gogolev所说,我认为我的文档课不是一个很好的例子而且没有很好的设计,所以我想我必须看看单一责任原则。
I could also implement some kind of ManagerClass that operates with my DocumentClass: 我还可以实现某种与DocumentClass一起运行的ManagerClass:
For example: 例如:
myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);
or 要么
myDocumentManagerObject.Copy(myConcreteDocumentObject, toPath);
but if I refer to approach 1) I would tend to create objects that perform their tasks by themself rather than other objects (DocumentManager) that do something with my DocumentObject. 但是,如果我参考方法1)我倾向于创建自己执行任务的对象,而不是使用我的DocumentObject执行某些操作的其他对象(DocumentManager)。
(I hope this will not take the direction of a religious discussion about OOP ;).) (我希望这不会采取关于OOP的宗教讨论的方向;)。)
[/EDIT] [/编辑]
At first this seems to be a very basic question like "when to use static methods and when not" but this is something I'm confronted every now and then (and I have difficulties to describe what the real problem is; perhaps it's just to get reasons why (not) to use 1) or why (not) to use 2)). 起初这似乎是一个非常基本的问题,比如“何时使用静态方法,何时不使用”,但这是我偶尔遇到的问题(我很难描述真正的问题是什么;也许只是为了得到原因(不)使用1)或为什么(不)使用2))。
(Although I'm using C#-Syntax this is not a C#-restricted problem) (虽然我使用的是C#-Syntax,但这不是C#限制的问题)
In OOP there are two approaches (amongst others) of working with objects: 在OOP中,有两种处理对象的方法(以及其他方法):
1) If I want my object to do something, I just tell him to do so: 1)如果我想要我的对象做某事,我只是告诉他这样做:
myConcreteObject.DoSomething();
It's just like talking to an object. 这就像和一个对象交谈一样。
2) Or if you're a fan of static methods: 2)或者如果你是静态方法的粉丝:
ObjectClass.JustDoIt();
In some way I think static functions just "feel" better. 在某种程度上,我认为静态函数只是“感觉”更好。 So I tend to use static methods very often (to be independent from a concrete instance - independency is always good thing).
所以我倾向于经常使用静态方法(独立于具体实例 - 独立性总是好事)。
So, when designing a class I often have to decide if I take approach 1) or approach 2): 所以,在设计课程时,我经常要决定是采用方法1)还是方法2):
Imagine you have a class "Document" which should stand for a document that should be saved into a database: 想象一下,你有一个“文档”类,它应该代表一个应该保存到数据库中的文档:
A Document 一个文件
Now I'm confrontated with several ways to create this class: 现在我遇到了几种创建这个类的方法:
//----- 1) non static approach/talking to objects -----
Document newDocument = new Document();
// Copy document to x (another database, for example)
newDocument.Copy(toPath);
I like this: I tell the document to copy itself to database x and the object does so by itself. 我喜欢这样:我告诉文档将自己复制到数据库x,对象本身就是这样做的。 Nice.
尼斯。
//----- 2) static approach ----------------------------
Document.Copy(myDocumentObject, toPath);
Why not? 为什么不? Also nice, feels very handy...
也不错,感觉非常方便......
So, which one to implement? 那么,实施哪一个? Both?
都? Or putting the static approach to a kind of helper class?
或者将静态方法放到一种辅助类中? Or choose approach 1) and stick with it to not weaken the interface of my Document-class?
或者选择方法1)并坚持使用它不会削弱我的Document类的界面?
When thinking about both approaches I come to the conclusion that (in theory) one could implement any function as a static function: 在考虑这两种方法时,我得出的结论是(在理论上)可以将任何函数实现为静态函数:
Class.Function(aConcreteClassObject, parameters);
but also non-static: 但也是非静态的:
aConcreteObject.DoSomething(parameters);
To give a real-world example: 举一个现实世界的例子:
[EDIT(Added parameter fromPath "Sorry, I forgot")] [编辑(从路径添加参数“对不起,我忘了”)]
//----- 2) static approach ----------------------------
File.Copy(fromPath, toPath); // .Net-Framework-like
[/EDIT] [/编辑]
but also: 但是也:
//----- 1) non static approach ------------------------
ExampeFileClass fileObject = new ExampleFileClass();
fileObject.Copy(toPath);
or even (kind of OOP-Overkill): 甚至(OOP-Overkill的种类):
//----- 1) non static approach, too -------------------
fileObject.ToPath = @"C:\Test\file.txt"; // property of fileObject
fileObject.Copy(); // copy to toPath
So, why (not) to use 1) or why (not) to use 2)? 那么,为什么(不)使用1)或为什么(不)使用2)?
(I would not concentrate on the Document class example too much, since it's more a general question about good class design.) (我不会过多地关注Document类示例,因为它更像是一个关于良好类设计的一般性问题。)
Here we go. 开始了。
First off: 首先:
So I tend to use static methods very often (to be independent from a concrete instance - independency is always good thing).
所以我倾向于经常使用静态方法(独立于具体实例 - 独立性总是好事)。
Quite the contrary: when using static methods you're very dependent on the concrete instance. 恰恰相反:使用静态方法时,您非常依赖于具体实例。
As far as your Document
is concerned, I'd go neither way. 就你的
Document
而言,我不会这样做。 You've listed all responsibilities of Document
class, which includes aggregation of data, saving itself to the database plus operations on pages and copying. 您已经列出了
Document
类的所有职责,其中包括数据聚合,将自身保存到数据库以及页面上的操作和复制。
This is way to much. 这是很多的方式。 Per SRP , each "module" (here "module" used as a catch-all term) should have only one reason to change.
根据SRP ,每个“模块”(此处“模块”用作全能术语)应该只有一个原因需要改变。 Your
Document
has lots of responsibilities, hence it has a whole slew of reasons to change. 您的
Document
有很多责任,因此它有很多改变的理由。 This is no good. 这不好。
With that in mind, I'd move all logic to other classes with strictly defined responsibilities. 考虑到这一点,我会将所有逻辑移到其他具有严格定义职责的类中。 A more or less accepted criterion of what to move was introduced, I believe, by either Herb Sutter or Andrei Alexandrescu, an is as follows: all operations (think methods) that can be performed with an object through its public contract should be moved outside the object in question.
我相信,Herb Sutter或Andrei Alexandrescu引入了或多或少可接受的移动标准,如下所示:所有可以通过公共合同与对象一起执行的操作(思考方法)应该移到外面有问题的对象。
You cannot use static methods to implement an interface, and you cannot override static methods. 您不能使用静态方法来实现接口,也不能覆盖静态方法。 So using static methods means that you are simply not doing OOP.
所以使用静态方法意味着你根本就不做OOP。
Think about how you would implement the following functionality using only static methods? 想想如何仅使用静态方法实现以下功能?
interface IDocument
{
void Print(IDevice targetDevice);
}
IDocument instance;
instance = new PdfDocument();
instance.Print(printer);
instance = new WordDocument();
instance.Print(printer);
KISS. 吻。 If you don't have to call a constructor, even better.
如果你不必调用构造函数,那就更好了。
Also, a method being static should tell you a little about how the function operates: 另外,一个静态方法应该告诉你一些函数如何运作:
There are some other important things to note: 还有一些需要注意的重要事项:
I would also refer to this thread , and a simple google search which frankly provides copious amounts of discussion on this very topic. 我也会参考这个帖子 ,以及一个简单的谷歌搜索 ,坦率地提供大量关于这个话题的讨论。
My "rule" is: 我的“规则”是:
In general if you have method like: 一般来说,如果你有这样的方法:
Document.Copy(myDocumentObject, toPath);
I think it is better to use a non-static method, because the first parameter being a Document suggests that it is really an operation on the document. 我认为最好使用非静态方法,因为第一个参数是Document,表明它实际上是对文档的操作。
In general, when programming using an OO mindset, you're going to want to avoid using static methods. 通常,在使用OO思维模式编程时,您将要避免使用静态方法。 In OOP, the idea is to represent everything as objects, and to give each object a clear set of abilities that represents its core abstraction.
在OOP中,我们的想法是将所有东西都表示为对象,并为每个对象提供一组清晰的能力来代表其核心抽象。 Static methods "break" this abstraction.
静态方法“打破”这种抽象。
Your example talking about a Document class with a copy method is a prime example. 您使用复制方法讨论Document类的示例就是一个很好的例子。 I would argue that the correct OO implementation is the first way .
我认为正确的OO实现是第一种方式 。 That is, to have copy as an instance method like this:
也就是说,要将副本作为这样的实例方法:
document1.copy(toPath)
It makes sense that the ability to copy itself is part of a Documents core abstraction. 复制自身的能力是文档核心抽象的一部分是有道理的。 In this way, the client code sending the copy message only has to specify where to copy to , because it is understood that a Document keeps track of where it is located internally.
通过这种方式,发送复制消息的客户端代码只需指定要复制到的位置 ,因为可以理解文档会跟踪内部的位置。 There is no need for that information to be replicated anywhere else, which is a major problem with the third option you present that looks like this:
没有必要在其他任何地方复制该信息,这是您提供的第三个选项的主要问题,如下所示:
Document.copy(fromPath, toPath)
If you have to ask, don't use statics. 如果你不得不问,不要使用静力学。
Actual rule of thumb (and there are plenty of real technical reasons but I find this helps explain the concepts): 实际的经验法则(有很多真正的技术原因,但我发现这有助于解释这些概念):
If the class in question can exist multiple times it's not static. 如果有问题的类可以多次存在,那么它不是静态的。
If the method in question acts against the instance information it's not static. 如果所讨论的方法对实例信息起作用,则它不是静态的。
If the method or class is about meta-information it's static. 如果方法或类是关于元信息的,那么它是静态的。
With those guidelines it's clear that files and documents are multiples and copying is an act against the instance. 根据这些指导原则,文件和文档很明显是倍数,复制是针对实例的行为。 The method should not be static.
该方法不应该是静态的。
Static Methods are can be very useful, I love extension methods, but they force coupling and if used improperly can make testing a nightmare! 静态方法可能非常有用,我喜欢扩展方法,但它们强制耦合,如果使用不当可能会使测试成为一场噩梦!
A good example of when to use a static is when you want to do so validation 何时使用静态的一个很好的例子是你想要进行验证
public static errors Validate(Document myDoc)
{
..some validation code
}
this is very testable and it doesn't mater that your tightly coupling the method to an object. 这是非常可测试的,并且它不会使您将方法与对象紧密耦合。 A Bad place to use a static method is when it dose something other then just return something, an example would be in a Biz layer that validates an object and if it passes validation it save the data to the DB
使用静态方法的不好的地方是当它给其他东西加剂然后只返回一些东西时,一个例子是在验证对象的Biz层中,如果它通过验证它将数据保存到DB
public static errors ValidateAndSave(Document myDoc)
{
errors docErrors = Validate(myDoc);
if(docErrors.count==0)
{
docErrors = SaveToDB(myDoc);
}
return docErrors;
}
This is a real pain to test because every time you run it, and it passes validation your taking to the database, your Biz logic may not generate an error but but your DAL layer might, so instead of only testing the functionality of the Biz layer your also having to test the DAL layer as well, and your tightly coupling your object, your Biz layer and your Dal together making this very hard to test and maintain. 这是一个真正的测试难题,因为每次运行它,并且它通过验证您的数据库,您的Biz逻辑可能不会生成错误,但您的DAL层可能,所以而不是只测试Biz层的功能您还必须测试DAL层,并将您的对象,Biz层和Dal紧密耦合在一起,这使得测试和维护非常困难。
In general, I would say that "copying" oneself, as far as an object is concerned, usually means cloning one's data into a new object. 一般来说,我会说,就对象而言,“复制”自己通常意味着将一个人的数据克隆到一个新对象中。 The "copying" described here is something the filesystem is doing on your behalf, not the object.
这里描述的“复制”是文件系统代表你做的事情,而不是对象。 As such, I'd make it a static method and not a method on a Document instance.
因此,我将它作为静态方法而不是Document实例上的方法。
Same as altCongnito, and i will add that fileObject.Copy everybody will use, more than the object fileObject. 与altCongnito相同,我将添加每个人将使用的fileObject.Copy,而不是对象fileObject。 Static for a function that have ideal relationship with the class and not functional dependency of it.
静态的函数与类具有理想的关系而不是函数的依赖性。
If you use any other objects then you shokld default to instance level methods so that you can configure those dependencies using Dependancy Injection. 如果您使用任何其他对象,则将shokld默认为实例级方法,以便您可以使用Dependancy Injection配置这些依赖项。
For example, if one of those images was an SVG image then you may have a dependency on an XML parser which (in Java at least) have many implementations, likewise for SVG renderers I imagine and many other constituent image types may require similar arrangements that evolve as the state of the object evolves or which must be changed in different usage scenarios (eg test, production, different projects re-using your code). 例如,如果其中一个图像是SVG图像,那么您可能依赖于XML解析器(至少在Java中)具有许多实现,同样对于我想象的SVG渲染器,许多其他组成图像类型可能需要类似的安排,随着对象的状态演变或必须在不同的使用场景中进行更改(例如测试,生产,重新使用代码的不同项目)。
The blinking amber warning light is that you may be using classes that are not part of your framework's default libraries, so you've made a choice of a third party component and if using statics you are not well placed to modify that decision. 闪烁的琥珀色警告灯表示您可能正在使用不属于框架默认库的类,因此您可以选择第三方组件,如果使用静态,则无法修改该决策。
A useful "redline" is that if you touch another process (database server, web service etc) then I'd regard a static method as bad 100% of the time as this makes unit testing more dificult. 一个有用的“红线”是,如果你触摸另一个进程(数据库服务器,Web服务等),那么我会认为静态方法在100%的时间都不好,因为这会使单元测试更加困难。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.