views:

334

answers:

2

Many people know this article: more on getters and setters. I think it does a convincing job of portraying the evil side of getters/setters. I've also tested it by trying to convert an existing project (unfinished) to code without getters/setters. It worked. Code readability improved greatly, less code and I've even managed to get rid of getters/setters where I initially thought they really were necessary. Except for one place.

Getting models to the view part is where I think this approach misses the point. In the article the author uses a builder to export the model. The problem is: there's just as many control over what is put into the builder as what you would have gotten with getters. Yes it hides the implementation, the way it is represented in the model. But getters don't get out of the model something very different from what was put in there. If you create a Money object passing '5' through the constructor, money.getAmount() won't return this converted to some other currency or as an array with one element '5' in it.

What you set you get. And through the view we set values, and those values we expect when we ask them (get) from an object that is supposed to hold what we set in the first place. A builder to export these just expects the same.

This is a bit long for a question. But I would like to be challenged on my view. Are getters and setters evil for transporting model-data to the view layer?

There are a lot of people who think getters/setters are not evil at all. This is also not what I would like to hear defended, as I think they DO are evil in other places than those I mentioned.

+1  A: 

For very simple cases, a data object doesn't have any behaviour to encapsulate, so arguments based on improving the encapsulating of behaviour don't really apply.

Most of the views I've built have been event driven. In an event driven view, you register for a change event on the model and update the view when the model changes, rather than passing 'the model' around and getting value of each attribute, then updating if its state has changed. Given that the event mechanism allows the model to push its state to the view, the view doesn't need getters to pull the state ( and if the model is also a listener, you don't need builders ). If you only change one attribute in a model with thousands of attributes, how well would a builder and passing a new model to the view work?

If instead of thinking about a model as a glob of data, but instead think about it as implementing a cache in the forwarding of state notification events from the builder/persistence layer to the listeners/views, then it's easy to see how it has behaviour which can be encapsulated rather than being purely state which can be polled.

Pete Kirkham
The model pushes some data to the view, but that's more or less the same than getting the data. Do you expect a different outcome between StackOverflowPost.getTitle() and StackOverflowPost.RegisterObserver(view) where the view then gets the (get)title pushed?
koen
On a side note: are observers used in this way not a way of wanting to be notified when a 'getSomething' changes?
koen
'data object' is the name for 'structure' in everything is an object languages.
Pete Kirkham
> On a side note: are observers used in this way not a way of wanting to be notified when a 'getSomething' changes?Yes, especially in networked applications where a notification with payload 'foo became 7 at 29843214324 ms UTC' costs one message latency but a 'foo has changed', 'what's foo then' 'foo=7' costs three, and is more easily confused if the data's changing at rates close to the latency.
Pete Kirkham
+1  A: 

There is an alternate model, used in the Scala language, but which can really be used anywhere. It's the Constructor/Extractor model. Constructor is just that, the constructor of a class. The extractor is a method which, when called, will return the parameters which, passed to a Constructor, will create a clone of this object.

For dynamic languages, you just return a list and be done with it. For statically typed languages, you can go the way of a list of objects, which must then be processed to that each type can be correctly assigned, or you must have a type-parameterized tuple class, so that you can return each parameter with the correct type.

In the specific case of Scala, its Extractors are similar to Java's static methods, and they receive an object as input. It either returns the parameters, or it returns None, which performs a function analogue to Java's null.

The idea is that you can decompose what you composed, which is pretty much what a view might want.

Now, another notion you might have is that "tell, don't ask" intends to keep business rules with the data it applies to. Now, the business rules of a view necessarily belongs with the view, so you are left with the problem of having to ask the model for the data... if you don't invert the game. The model might tell the view to display data, passing the relevant fields to it instead of being asked for them. So the model tells the view to display data, and the view tells the model to update it.

Daniel