Reputation: 2567
[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.
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. 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
Document.Validate(myDocumentObject);
but also
myConcreteDocumentObject.Validate();
To get back to my Copy()-example one could implement Copy() like
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 :)).
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.
I could also implement some kind of ManagerClass that operates with my DocumentClass:
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.
(I hope this will not take the direction of a religious discussion about 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)).
(Although I'm using C#-Syntax this is not a C#-restricted problem)
In OOP there are two approaches (amongst others) of working with objects:
1) If I want my object to do something, I just tell him to do so:
myConcreteObject.DoSomething();
It's just like talking to an object.
2) Or if you're a fan of static methods:
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):
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. 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?
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):
//----- 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)?
(I would not concentrate on the Document class example too much, since it's more a general question about good class design.)
Upvotes: 14
Views: 11357
Reputation: 1871
In general, when programming using an OO mindset, you're going to want to avoid using static methods. 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. Static methods "break" this abstraction.
Your example talking about a Document class with a copy method is a prime example. I would argue that the correct OO implementation is the first way. 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)
Upvotes: 2
Reputation: 4818
If you use any other objects then you shokld default to instance level methods so that you can configure those dependencies using 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 (e.g. test, production, different projects re-using your code).
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.
Upvotes: 0
Reputation: 20802
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
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.
Upvotes: 1
Reputation: 51312
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.
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);
Upvotes: 9
Reputation: 41401
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.
Upvotes: 9
Reputation: 75872
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.
Upvotes: 1
Reputation: 115897
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. You've listed all responsibilities of Document
class, which includes aggregation of data, saving itself to the database plus operations on pages and copying.
This is way to much. Per SRP, each "module" (here "module" used as a catch-all term) should have only one reason to change. Your Document
has lots of responsibilities, hence it has a whole slew of reasons to change. 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.
Upvotes: 16
Reputation: 56
Same as altCongnito, and i will add that fileObject.Copy everybody will use, more than the object fileObject. Static for a function that have ideal relationship with the class and not functional dependency of it.
Upvotes: 0
Reputation: 72015
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.
Upvotes: 0
Reputation: 36689
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.
Upvotes: 3
Reputation: 8269
My "rule" is:
Upvotes: 6