views:

1851

answers:

11

[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]


Old Version:

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

  • consists of one or more image files from filesystem (these become the single document pages)
  • has something like a bibliography - fields the user can add information about the document to - which is saved to an extra file
  • and should have some operations like Copy(), AddPage(), RemovePage() etc.

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.)

+7  A: 

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:

  • It doesn't operate on variables outside of what's passed to it.
  • It doesn't require any memory other than when the method is called (not counting what is returned from the function)

There are some other important things to note:

  • Static methods in some instances (Java) are not able to be overridden/subclassed, so they are better suited for cases where the implementation will not need to change.
  • Some would argue that static methods are intrinsically difficult to test.

I would also refer to this thread, and a simple google search which frankly provides copious amounts of discussion on this very topic.

altCognito
Your second bullet is a good one since dependencies utilise memory and, of course, you nearly *always* have some sort of dependency. Therefore, your second bullet actually implies that no interesting method will be static, which feels about right. I disagree that a constructor adds complexity, its adds a line of code, but object instances aid abstraction, reducing complexity and are thereforee KISS compliant.
Simon Gibbs
It's twice the code. It introduces using an instance which leads to the absolutely most common failure in programming: Dereferencing a null object. I would cringe if every time I needed to do an xpath query, create a hash (well, some languages anyway), or simply copy a file I had to create an instance.
altCognito
Static methods have their place, though I agree with Anton in that this is not likely one of those places based on what was being proposed.
altCognito
Well, those aren't really that interesting as methods go.
Simon Gibbs
+4  A: 

My "rule" is:

  • If I don't need to use properties from my class, make it static. (in other words, if the method is not really attached to the class, just there for logic association, use static )
Sergio
Consider virtual methods and interface implementations. But this is actually as it is proposed by the code analysis ("performance").
Stefan Steinegger
I have be more precise: this applies to private members only!
Stefan Steinegger
Stefan, I think you are not understanding what I said. It's the same as altCognito, just different words.
Sergio
+1  A: 

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.

Grzenio
A: 

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.

mquander
A: 

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.

Chocolim
+15  A: 

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.


Anton Gogolev
Are you saying that a class should have no public methods?
Svish
But should those methods when he moves them be static?
altCognito
Absolutely no. What I say is that if some operation can be implemented only in terms of public contract of the class in question, this operation should not be a part that class.
Anton Gogolev
@altCognito It depends. I prefer not to use static methods since they couple code too much.
Anton Gogolev
So say I have a class Polygon, and want to calculate various (many!) things about it (centre of mass, distance to another polygon, etc). Where should these methods live? If I have a different class for each type of calculation, doesn't it make eg discoverability via IntelliSense very difficult?
Joel in Gö
+8  A: 

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);
Groo
+1  A: 

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.

annakata
+1  A: 

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.

Bob The Janitor
A: 

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.

Simon Gibbs
+1  A: 

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)
Nick Stamas