开发者

Object vs static method design [closed]

Closed. This question is opinion-based. It is not currently accepting answers.

Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.

Closed 12 months ago.

Improve this question

As shown below, there are two straightforward ways I could make a stream copier (bar introducing Apache Commons or similar). Which one should I go for, and why ?

public class StreamCopier {
private int bufferSize;

public StreamCopier() {
    this(4096);
}

public StreamCopier(int bufferSize) {
    this.bufferSize = bufferSize;
}

public long copy(InputStream in , OutputStream out ) throws IOException{
    byte[] buffer = new byte[bufferSize];
    int bytesRead;
    long totalBytes = 0;
    while((bytesRead= in.read(buffer)) != -1) {
        out.write(buffer,0,bytesRead);
        totalBytes += bytesRead;
    }

    return totalBytes;
}
}

vs

 public class StreamCopier {

 public static long copy(InputStream in , OutputStream out)
     throws IOException {
     return this.copy(in,out,4096);
 }

 public static long copy(InputStream in , OutputStream out,int bufferSize)
     throws IOException {
     byte[] buffer = new byte[bufferSize];
     int bytesRead;
     long totalBytes = 0;
     while ((bytesRead= in.read(buffer)) != -1) {
         out.write(buffer,0,bytesRead);
         totalBytes += bytesRead;
     }

  开发者_开发问答   return totalBytes;
}
}


I'd go with the non-static (instance) version, and supply it to consumers as an explicit dependency with a setter:

  • mocking it out for unit testing is then trivial, so tests of consumers aren't coupled to the implementation;
  • swapping out functionality is straightforward, eg: using a subclass;
  • works nicely with dependency injection systems.

Edit

In response to a (useful!) comment of "how does this help mocking?", here's how it might work:

class ThingThatUsesStreamCopier {

    // our copier instance. set in constructor, but might equally use
    // a setter for this:
    private StreamCopier copier;

    public ThingThatUsesStreamCopier(StreamCopier copier) {
        this.copier = copier;
    }

    public void makeCopy(Stream in, Stream out) {
        // probably something a little less trivial...
        copier.copy(in, out);
    }
}

When I come to test ThingThatUsesStreamCopier, I can create a mock object version of a StreamCopier and instantiate the ThingThatUsesStreamCopier using this mock.

By doing so, I have full control over the behaviour of my mock, so my test is decoupled from any real implementations of StreamCopier. I am only testing the consumer, not the consumer plus the consumed.


I would go for the static version because there is no state.

There is generally no point in a stateless object unless you need it for inheritance purposes (virtual methods).

If the users are likely to want to mock out the functionality then I would prefer an interface over a concrete implementation - the implementor of the interface could not be static so in this case you would have to use an instantiated object.

Edit: A couple of years later and I now wish to castigate my former self for suggesting the static version. I would go for the instance version with no hesitation whatsoever these days.


I'd go with the static version.

There's no need for an object as you're not storing state, so why make the caller create an object just to call a method.


It all depends on the usage pattern. Maybe you just need to copy something from an InputStream to an OutputStream every now and then? Then it probably won’t matter. However, if you’re doing lots of copying in various environments (network streams, both LAN and WAN, copying files on the local disk) you might be better off when you have the option to select the size of the buffer used for copying.

So, why restrict yourself to only one method? Implement it with object methods and a constructor that takes a buffer size (used for your varying needs), and maybe add a static method to get a pseudo-singleton instance that uses some default buffer size (which is used for the casual copying every now and then).


If you go for static you should avoid WET names.

WET stands for write everything twice, thus instead of StreamCopier.copy call it

Copy.stream(in,out)

that way your code reads more like English.


There will be minimal difference in overhead (the static will be allocated once vs allocation on instance basis) especially given that the state consists of a single int. Generally I would rarely go for static classes as they make unit testing difficult. There is little overhead in making classes instance based rather than static (an allocation, zero'ing out memory and calling the constructor - which are all v quick operation) and due to the inability to mock out statics I see little benefit.

Amongst other things static class can also dramatically increase coupling; a static class can be referenced from anywhere as long as the assembly reference is referenced. When it comes to refactoring this can lead to problems (e.g anything the staitc references internally is dragged into the dependency graph etc.).


public static long copy

You don't need an instance to execute the method because you're not storing state, and you are not planning to have subclasses out of this.

I would just add the final keyword.

Auxiliary methods like this are good usages of class methods vs. instance methods.


no matter what to use at this time, but you shuld think, what would you need in future. Maybe you have som plans extending buffer operations or something. I'd choose non-static methods.


Since I don't see any big performance differences I think this is simply a practicality question and in my opinion the static method is alot more practical ;-).


It would depend on the usage. Does the code that calls the copy know what an appropriate buffer size is? It could be that the decision is better off been made outside of that code and a StreamCopier instance is a better thing to pass around as a parameter than a buffer size (e.g. if it turned out that an extra parameter was needed at a later stage no code changes would be needed)


The static method means coding to a concrete class, not an interface. It means tighter coupling and makes Unit Testing harder. This is where the 'does it contain state' rule falls down.


When you user Static method, you call it any time it will return the same Object, but you create new A() it will create new Object when you work with it

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜