Why are setters and getters bad for Object Oriented design I have had this discussion like a dozen times already so I thought I could write it all down.
In many cases it is not that big deal. The problem is that people seem to be blind and ignore the fact that accessors can cause design issues. Its more about principles and overall rules. You wont get swine flu and die if you keep on using getters and setters. So don't panic! But your code may be cooler and more coherent if you stop for a minute and consider should they be there.
Its not matter of life and death but there is so much code out there with millions of accessor methods that we have to start thinking about it as a problem.
There is a big difference between setters and getters that actually are necessary and those that are just thrown in by default or other wrong reasons.
So what is the difference you ask?
For what reasons do people use setters and getters?
I think these are main reasons why developers would add getters and setters to their code:
- IDE / framework support requires it
- Java beans have this stupid convention of adding getters and setters for every member
- Dependency injection
- Instance initialization
- Lack of knowledge how class will be used
- Because developer knows public members are an anti pattern
- Instance configuration
- Runtime instance state changes / inspection
- Data transfer objects
- ORM model objects
What can happen if you overdose getter and setter methods?
Getters and setters can cause some of the following symptoms:
- Bloat the interface
- Increase coupling
- Decrease encapsulation
- Increase risk of misuse or call sequence errors
Which are the wrong reasons to use getters and setters in OO code?
No.1. IDE support requires it
Many languages especially Java and C# require developers to add getter and setter methods for the IDE to allow bean configuration. Yes maybe it does look cool you can inspect your objects in the IDE but does it make your code better? No. It is only to allow bean-like editing.
No. 2. Java beans have this stupid convention
People see it everywhere so they think it is how things should be done. If enterprise giants say that this is the way to do it then who are we to argue?
Well we have all the rights to argue. If you follow Java evolution you will see how many design mistakes have been made and how much junk was deprecated or still is inconsistent.
Java beans was a easy way to allow frameworks and IDE's support and methods discovery. It was not created to enhance design nor decrease coupling.
Enterprise does not mean better, it only means potentially bigger and more complex. Do not be afraid to question their methods.
No. 3. Dependency injection
Many people use setters to allow dependency injection. If you have a setter (to set lets say logger) then framework can call that method and inject the (logger) instance for you. It sounds good. The only problem I have with this approach is that you should not allow people to call this method. Its not for public use to inject new loggers once instance is ready to go.
My argument is that unless you code only against interfaces you should not use setters for dependency injection. Even if you do use interfaces only I would feel safer to use constructor based dependency injection.
If other developers cant break stuff then they will not. I have seen tons of crazy constructs and most of them were created because developer had too much freedom ; )
Another problem with this approach of injection is that you might end up with setters that have to be called in particular order if they are more complex than just setting values.
A slight problem with constructor based dependency injection you might came across is circular dependencies in the construction graph. In such cases you might actually have to use setter injection as you wont be able to create all instance as the same time. It should not really happen too often unless you have insane coupling and dependencies rules where everything depends on everything.
No. 4. Instance initialization
That is the case where developers says 'ok I create and instance by hand and then set a few values using setters, then call some initialization method and im ready to go'.
This is just horrible thing to do. You should not force clients of your class to know what is the order of method calls. You should not have prepare/initialize/process/postprocess nonsense in your classes.
In some cases it might make sense to call methods in particular order but forcing it is always a potential code smell and makes code much more difficult to use.
No. 5. Lack of knowledge how class will be used
Developers sometimes are not sure how will the class be used so they think they should allow more flexibility. What is the most common and easiest way to 'add flexibility' ? Adding setter methods.
If you do not know how is the class going to be used you have a big chance of screwing up the design any way. Better do the homework first or restrict a few use cases but make the class actually work well in these cases. Well designed class should do one thing and do it right. The smaller the responsibility the easier it is to maintain and understand the code.
No. 6. Because developer knows public members are anti pattern
'Public members are an anti pattern, you should not use them, lets use setters instead'.
What is the difference between public member and public setter? Not much, only thing you can do is rename the member or do some extra things like validation.
How often does setter have anything more than assignment? Maybe in 1% of the cases. To me public setters is not really much better than a public member. You are exposing internal state and logic to external classes. You increase coupling, bloat interface and make more difficult to change the internal implementation.
No. 7. Instance configuration
If you can not set up your instance during creation something might be wrong. Why would you need to configure your object once its created? Is constructor not enough?
Especially languages like PHP where you have a lot of freedom in parameters passing you should be able to easily create instances based on configuration or any parameters. If its not enough create factories or builders that will allow more options or creation methods.
My point is, create instance, use it. Not create instance, do configuration, use it. If instance is create it should be ready to go and no one should worry what did we miss.
Not so wrong reasons for using setters
In some cases limited usage of getters and setters would be ok as well.
No. 8. Runtime instance state changes / inspection
In some cases you create and instance of a class and you still have to allow users to change its state. In these cases it might be necessary to use setters and getters.
Example of such use would be music player, you need to allow class clients to call setVolume at any time. In this case I don't see problem with setters as they are really necessary.
Example of case when setters are not necessary would be a simple caching class. You initialize it with all the configuration and dependencies it needs and then you just want to call set/get/delete etc on objects stored in the cache store. Do you need a method to change key prefix? I don't think so. Well at least I did not have the need. Do you need to set default TTL? No if you can set it during construction.
So when using getters and setters is not a problem?
I think there are some situations that adding setters and getters is ok. I believe it is in cases where object does not really do any work and its sole purpose is to hold state.
Examples of it would be:
No. 9. Data transfer objects
Data is stored in and object to be sent over soap call or other transfer protocol. It could also be used to make modules of the application less coupled by adding a layer of interfaces between modules.
No. 10. ORM model objects
In Object Relational Mapping people use classes to represent database entries. I think in this case its also fine to use setters and getters as this is basically all the class does. Its supposed to hold state and let clients access it. It also needs way to alter the state.
More reading on why getters and setters are abused or even evil
Summary
It is the most difficult to make the difference when is it really necessary to have a getter / setter methods.
I believe that as long as you stop to think for a second before you add them you should be doing a good job. Its not like setters and getters are evil, you just need to think what you are doing. The whole issue just about too much code out there with too many of getters and setters.
Keep in mind that adding getter and setter you allow any client of the class to use them. Every time you want to refactor the class you will need to locate these places. Every time you want to change/add/remove a member you have to check where and how is it set or get.
Just try to keep your privates private and you will be fine!
Comments
First of all sorry for such a
First of all sorry for such a late publish of the comments .... i had a crazy few months ... i am moving abroad next month but ill write a separate post about that.
Well. i don't really see a problem with getters and setters in your DTO (or persistent entities or however you pass database data around). I mean if you have a product in the database you will have to get its name at some stage no matter what you do. I also think it is not that bad if your setters and getters are hidden behind the public interface. In this scenario you allow closely coupled objects to access and replace values inside of the instance but any external user would access the instance via interface that does not expose the setters/getters any more. So in this scenario setters/getters become kind of package scoped ;- ) At least as long as you depend on interfaces only not concrete classes.
To make the point very clear. Setters and getters are necessary in some cases but we have to ask ourself a question "should they be added or not" before we add them.
I don't remember how ruby does it but in groovy setters/getters are transparent. So if object has method setName you can say instance.name='Tom' and groovy will call the setter. If you do not define setter it will be added by default. So you are using setters they are not coded unless you need to override the behavior. I think its a very neat solution. Less code and hassle but still allows to come back later on and add some logic if necessary.
cheers
I've been checking your blog
I've been checking your blog for days, waiting for my comment to be approved and see your response to it. I give up.
This was an interesting read.
This was an interesting read. I would like to hear more about your ideas on what to use instead of getters and setters. I pass beans around in my application all the time, they are loaded with data from the database and then passed around to views which call the getters to display data. When updating data, the bean is loaded up from the DB again, then the updated information is placed into the bean using the setters, then the bean is passed to a DAO which calls the getters and updates the database with that information.
Great post. Interesting you
Great post. Interesting you said g/s are okay for ORM model objects. I would be interested on your thoughts about Active Record/Rails not using g/a of their orm.
Post new comment