Hacker News new | ask | show | jobs
by spriggan3 3727 days ago
> The getX() and setX() is an anti-pattern of good OOP.

No it isn't, it provides encapsulation, which the most important aspect of OOP.

I agree with the rest.

3 comments

>No it isn't, it provides encapsulation,

The extensive use of getters()/setters() is a common misunderstanding of "encapsulation". It's an example of following the "letter of the law but not the spirit of the law".

Let's separate the idea of "encapsulation" into 2 categories:

(1) syntax encapsulation: private int x; public getX(); public SetX(); // letter of the law

(2) conceptual/semantic encapsulation: Object.DoSomething() that works on x internally // spirit of the law

It's the idea presented in (2) that follows the ideals of OOP design and helps reduce cognitive load. The common coding practice of (1) doesn't really provide "encapsulation" that helps make large scale programs more understandable. I also think (1) was exacerbated by codegen tools such as ORMs and GUI data binding frameworks. Therefore, inexperienced programmers thought that having a ton of gets()/sets() in their own manually handcrafted classes was "correct OOP".

Or to put it another way, encapsulation of state versus encapsulation of logic.
It can very easily break the encapsulation though. Now external processes are dependent on direct access to the internal state of your object, and if the object is refactored in the future you need to reprogram those getters and setters to return something that is still correct but may not represent the internal state of the object at all and may in fact be complex now.

An example of where this can all go wrong is if you have a TCP object that opens a connection to a remote server and then lets you read and write the socket. Someone decides that they need to find out what IP address the object used when it connected and create a get_ipaddr() method that returns a s_addr type. But then the TCP object is updated to support IPv6 and now the author needs to figure out how to return a V6 IP address to external methods that only expect V4.

The proper way to implement it might have been to move whatever logic was examining the IP address into the TCP object itself. Of course this is how you end up with horrendously complex objects with hundreds of methods all used exactly once somewhere in the code or exactly once in the code of some other project.

> An example of where this can all go wrong is if you have a TCP object that opens a connection to a remote server and then lets you read and write the socket. Someone decides that they need to find out what IP address the object used when it connected and create a get_ipaddr() method that returns a s_addr type. But then the TCP object is updated to support IPv6 and now the author needs to figure out how to return a V6 IP address to external methods that only expect V4

In that case you should use polymorphism. There is no reason why the consumer of the address returning the IP should know whether get_ipaddr returns an IPV4 or an IPV6 directly.

Getters and setters are an anti-pattern that works around a specific deficit in a programming language. In Python, if you want to refactor an object so that `foo.bar = baz` does something other than blindly set foo's bar to baz, you can. In Java, you can't, which is why setting foo's bar to baz is done with `foo.setBar(baz)`.