Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Let's say we're making a parser. One implementation could be:

public sealed class Parser1
{
    public string Parse(string text)
    {
       ...
    }
}

Or we could pass the text to the constructor instead:

public sealed class Parser2
{
    public Parser2(string text)
    {
       this.text = text;
    }

    public string Parse()
    {
       ...
    }
}

Usage is simple in both cases, but what does it mean to enable parameter input to Parser1, compared to the other? What message have I sent to a fellow programmer, when they look at the API? Also, are there any technical advantages/disadvantages in certain cases?

Another question comes up when I realize that an interface would be quite meaningless in the second implementation:

public interface IParser
{
    string Parse();
}

...where an interface on the first one could serve at least some purpose. Does that signify anything in particular, that a class is "interfaceable" or not?

share|improve this question

5 Answers 5

Semantically speaking, in OOP you should only pass the constructor a set of parameters which are needed to build the class - similarly when you call a method, you should only pass it the parameters it needs to execute its business logic.

The parameters that you need to pass in the constructor are parameters which have no sensible default value and if your class is immutable (or indeed a struct) then all-non default properties must be passed.

Regarding your two example:

  • if you pass text to the constructor, it hints that the Parser2 class will be specifically built to parse that instance of text at a later time. It will be a specific parser. This is typically the case when building the class is very expensive or subtle, a RegEx might be compiled in the constructor, so once you hold an instance you can re-use it without having to pay the cost of compiling; another example is initializing the PRNG - it's better if it is done rarely.
  • if you pass text to the method, it signals that Parser1 can be reused to parse different texts by calls.
share|improve this answer
2  
I'd add that there's a, weak, signal that Parser1 maintains state -- i.e. that a particular string of text may produce different results depending upon has previously been done on tat instance. This isn't necessarily so, but it may be. –  jmoreno Jun 5 '13 at 6:31

Well, let's recall what it means to pass a variable as constructor parameter: You initialize an object in order to use its instance variables in methods of the object. The point is that you probably want to use it in more than one method since you want to have a high cohesion in your class.

Passing a parameter directly to a method means in a way sending a message to an object and probably receive an answer. By that, the client wants the object to deliver a service for him.

So in conclusion, those are two very different means of passing parameters and you should choose whether your object should either deliver a service or provide some functionality inherently while managing some information internally.

share|improve this answer
    
+1. Cohesion is the how I decide whether it belongs on the method or constructor. –  jhewlett Jun 5 '13 at 0:51

The second version of the class can be made immutable.

The interface can still be used to provide the ability to swap out the underlying implementation.

share|improve this answer
    
Can't it be made immutable in the first version too, by passing data around within the class in a functional manner? –  ciscoheat Jun 4 '13 at 22:12
2  
Absolutely. But the general pattern of immutability is to set the class members using the constructor, and have read-only properties. For functional programming, you don't even need a class. –  Robert Harvey Jun 4 '13 at 22:48

Parser1

Building with a default constructor and passing input text into a method implies that Parser1 is re-usable.

Parser2

Passing the input text into the constructor implies that a new Parser2 must be created for each input string.

share|improve this answer
    
Sure, so if we take it to the next level, what to conclude about a re-usable object compared to a non-reusable? –  ciscoheat Jun 4 '13 at 20:26
    
I wouldn't assume any more than that, instead deferring to documentation. –  Mike Partridge Jun 5 '13 at 13:35

Usage is simple in both cases, but what does it mean to enable parameter input to Parser1, compared to the other?

Its a fundamental design shift. And design should convey intent and meaning. Do you need to have separate objects for every string you want to parse? In other words, why do we need an instance of parser with stringX and another instance with stringY? What is it about parse(ing) and the given string that the two must live and die together? Assuming that the "underlying [parsing] implementation" (as Robert Harvey says) does not change, there seems to be no point. And even then its questionable IMHO.

How does the concept of a class change when passing data to the constructor instead of method parameters?

Constructor parameters tell me these things are required for an object. Proper state is not guaranteed without them. Also, I know how/why one parser is fundamentally different from another.

Constructor parameters keep me from having to know too much about how to use the class. If instead I'm supposed to set certain properties - how do I know that? A whole can of worms opens up. What properties? In what order? Before I use what methods? and so on.

Another question comes up when I realize that an interface would be quite meaningless in the second implementation:

An interface, as in A.P.I., is the methods and properties exposed to client code. Do not get wrapped up in public interface { ... } exclusively. So the meaning of the interface is in the either-or constructor vs method parameter dilemma, NOT public interface Iparser vs public sealed class Parser

The sealed class is odd. If I'm thinking about different parser implementations - you did mention "Iparser" - then inheritance is my first thought. It's just a natural conceptual extension in my thinking. I.E. all ParserXs are fundamentally Parsers. How else to say it?... A German Shepard is a dog (inheritance), but I can train my parrot to bark (act like a dog - "interface"); but Polly is not a dog, merely pretending, having learned a subset of dogness. Classes, abstract or otherwise, serve perfectly well as interfaces.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.