views:

1484

answers:

11

What do people think of the best guidelines to use in an interface? What should and shouldn't go into an interface?

I've heard people say that, as a general rule, an interface must only define behavior and not state. Does this mean that an interface shouldn't contain getters and setters?

My opinion: Maybe not so for setters, but sometimes I think that getters are valid to be placed in an interface. This is merely to enforce the implementation classes to implement those getters and so to indicate that the clients are able to call those getters to check on something, for example.

+1  A: 

I don't see why an interface can't define getters and setters. For instance, List.size() is effectively a getter. The interface must define the behaviour rather than the implementation though - it can't say how you'll handle the state, but it can insist that you can get it and set it.

Collection interfaces are all about state, for example - but different collections can store that state in radically different ways.

EDIT: The comments suggest that getters and setters imply a simple field is used for backing storage. I vehemently disagree with this implication. To my mind there's an implication that it's "reasonably cheap" to get/set the value, but not that it's stored as a field with a trivial implementation.


EDIT: As noted in the comments, this is made explicit in the JavaBeans specification section 7.1:

Thus even when a script writer types in something such as b.Label = foo there is still a method call into the target object to set the property, and the target object has full programmatic control.

So properties need not just be simple data fields, they can actually be computed values. Updates may have various programmatic side effects. For example, changing a bean’s background color property might also cause the bean to be repainted with the new color."


If the supposed implication were true, we might just as well expose properties as fields directly. Fortunately that implication doesn't hold: getters and setters are perfectly within their rights to compute things.

For example, consider a component with

getWidth()
getHeight()
getSize()

Do you believe there's an implication that there are three variables there? Would it not be reasonable to either have:

private int width;
private int height;

public int getWidth() {
    return width;
}

public int getHeight() {
    return height;
}

public Size getSize() {
    return new Size(width, height); // Assuming an immutable Size type
}

Or (preferrably IMO):

private Size size;

public int getWidth() {
    return size.getWidth();
}

public int getHeight() {
    return size.getHeight();
}

public Size getSize() {
    return size;
}

Here either the size property or the height/width properties are for convenience only - but I don't see that that makes them invalid in any way.

Jon Skeet
That's not a getter. You don't know if size is computed or stored
Stephan Eggermont
+1. Beat me to it. Like it or not `getX` and `setX` imply that `x` is a property of an object in that the object has a variable `x` which is accessible through these methods.
oxbow_lakes
I don't agree with that implication. A getter is perfectly within its rights to compute the value if it wants to.
Jon Skeet
(Otherwise you might as well just expose the field and be done with it... the whole point of making it a method is to *hide* the implementation.)
Jon Skeet
(There are plenty of examples of this in the standard API, btw. String.getBytes, Currency.getSymbol, etc.)
Jon Skeet
Yes. A getter certainly doesn't imply an underlying field (I get the impression that this misconception is why some people claim getters/setters don't need to be unit tested, since they're 'trivial')
Brian Agnew
I'm sorry but I utterly disagree with both of you. Whilst from a coding perspective, it is not required that there is an underlying value, it seems to me a clear **implication** from the perspective of JavaBean conventions. People declaring methods `setX` and `getX` that are *not* just accessing an underlying variable are playing with fire because most people (IMHO) will assume that they are.
oxbow_lakes
I'd say it's making that assumption which is playing with fire, given that the Java API is stuffed full of things, and for good reason. I'd say the **implication** is that because you're calling a method rather than accessing a field directly, you *shouldn't* assume that it'll do nothing. If I really want to communicate that there's just a field to be accessed, I'll expose a field.
Jon Skeet
The JavaBeans specification *also* disagrees with you. From section 7.1: "So properties need not just be simple data fields, they can actually be computed values. Updates may have various programmatic side effects. For example, changing a bean’s background colorproperty might also cause the bean to be repainted with the new color."
Jon Skeet
If you assume getWhatever() simply returns the value of field 'whatever', then someday (soon) something's going to prove you wrong
Brian Agnew
These are all good points. However, just because something is wrong doesn't mean that people won't make certain assumptions or have particular perceptions of it. I for one, won't be saying "niggardly" anytime in public soon.
oxbow_lakes
As from what you reference above - you are clearly correct. I will still avoid using `setX` methods where there is no such property `x` as I think most people will make that assumption, even if it is an invalid one.
oxbow_lakes
It **also** says in the specification: *Typically a bean’s properties will be persistent, so that their state will be stored awayas part of the persistent state of the bean.* So, typically, one would expect a `setX` method to be backed by a property
oxbow_lakes
"Part of the persistent state" != "A field of that type". Persistent state could be held in a map, or as part of some larger type (as in the width/height/size example I showed).
Jon Skeet
+2  A: 

I don't think a bean should have an interface on top of it, in general. A javabean is an interface in the more general meaning. An Interface specifies the external contract of something more complex. A javabean's external contract and its internal representation are identical.

I wouldn't say that you shouldn't have getters in an interface, though. It makes perfect sense to have a ReadableDataThingie interface that is implemented by DataThingieBean.

Kevin Peterson
A: 

For further reading: Practical API Design Confessions of a Java Framework Architect (Jaroslav Tulach, 2008, Apress).

kd304
+1  A: 

This touches upon the whole Getter/Setters are evil topic which is addressed multiple times on this site and elsewhere.

I tend to favour not having accessors in the interface, but to add collaborators using constructor arguments to the implementation.

Paul McKenzie
+1  A: 

The fact that the straightforward implementation of something is as a getter shouldn't stop it being in an interface if it needs to be.

soru
I don't think the implementation details determine whether something's in the interface. Rather, is it required by client objects to do their job ? If not, then it probably shouldn't be there
Brian Agnew
+1  A: 

I think that there are two types of interfaces declared in general:

  1. a service description. This might be something like CalculationService. I don't think that methods getX should be in this sort of interface, and certainly not setX. They quite clearly imply implementation detail, which is not the job of this type of interface.
  2. a data model - exists solely to abstract out the implementation of data objects in the system. These might be used to aid in testing or just because some people as old as me remember the days when (for example) using a persistence framework tied you down to having a particular superclasss (i.e. you would choose to implement an interface in case you switched your persistence layer). I think that having JavaBean methods in this type of interface is entirely reasonable.

Note: the collections classes probably fit in to type #2

oxbow_lakes
That's dangerously close to procedural programming.
Tom Hawtin - tackline
I can't tell whether you're joking :-/ If not, *what* is dangerously close to PP? And what exactly would be wrong with PP in any event?
oxbow_lakes
Presumably you mean me separating data from behaviour. It may well be old fashioned but ever since I wrote a "library" program in Smalltalk 10 years ago in this "lively community of objects" style, the only thing I remember about it is that I could never recall where my business logic resided. Did books loan themselves to customers? Or did the customers check out the books?
oxbow_lakes
In your above scenario, don't you need a librarian ?
Brian Agnew
Haha, yes. That is exactly what I needed - the logic on some central *manager*, not the data!
oxbow_lakes
+2  A: 

There's nothing inherently evil about getters/setters. However:

  1. I tend to make my objects immutable (in the first instance) with respect to the fields they contain. Why ? I instantiate most things during the construction phase. If I want to change something later then I relax those restrictions. So my interfaces will tend to contain getters, but not setters (there are other benefits - particularly threading).
  2. I want my objects to do things for me, not the other way around. So when one of my objects acquires a number of getters, I start to ask whether that object should have more functionality in it, rather than exposing all it's data for something else to work with. See this answer for more detail.

These are all guidelines, note.

Brian Agnew
Can whoever downvoted this indicate why ? Thx
Brian Agnew
A: 

I used those kind of interfaces, for example we had classes with fields beginDate, endDate. Those fields were in many classes and I had one use case I need to get those dates for different objects, so I extracted interface and was very happy :)

01
A: 

Basically if the answer to "Do I need to know the value of [state, property, whateverThignAMaGit] in order to work with an instance of it ?" then yes... the accessors belong in the interface.

List.size() from John above is a perfect example of a getter that needs to be defined in an interface

Newtopian
A: 

Getters are used to query the state of an object - which you can really avoid when designing your interface. Read http://www.pragprog.com/articles/tell-dont-ask

A: 

I've heard people say that, as a general rule, an interface must only define behavior and not state. Does this mean that an interface shouldn't contain getters and setters?

For starters, at least with Java and excluding Exception declarations, you cannot define complete behavior without state. In Java, interfaces do not define behavior. They can't. What they define are types; promises of implementing a set of feature signatures possibly with some post-conditions wrt exceptions. But that's it. Behavior and state are defined by classes implementing those interfaces.

Secondly, if getters and setters are defined in an interface, they don't really define complete behavior (other that one is for read and one is for write wrt a property.) You can have complex behavior behind setters and getters, but they can only be implemented in the actual classes. There is nothing in the Java language that can allow us to freely define behavior in interfaces except for the most restrictive of cases.

With that into consideration, there is nothing wrong - syntactically and semantically - with having setters and getters in interfaces.

If your application is well-modeled and the problem requires that you have an interface defining setters and getters, why not. For example, take a look at the ServletResponse interface.

Now, if we look at getters and setters from the point of view of implementing classes compliant with the JavaBeans specs, then you do not need to define interfaces for them.

But if you have things that require setters and getters, like a bean might, and which is also required to be plugged at compile-type (not at run-time like a bean might), and for which multiple implementations might exist, then yeah, this would call for an interface defining getters and setters.

Hope it helps.

luis.espinal