神刀安全网

Doing it wrong: getters and setters

Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling. A profusion of getters and setters (also referred to as accessors, accessor methods, and properties) is a sign of a poorly-designed set of classes.

A long time ago programmers discovered that reducing the scope (visibility) of data as much as possible led to more reliable and maintainable code. Before programming languages supported encapsulation or objects, programmers who cared to write better code followed best practices and idioms (what would be called patterns today) that encouraged limiting scope and data hiding. Back in the old days these ideas were discussed in terms of module strength and coupling. To learn the concepts without the distraction of OOP and “design patterns” terminology see Glenford Myers’ books “Reliable Software Through Composite Design” and “Composite/Structured Design” .

Today most of the popular programming languages support objects, limiting scope, modularity, passing by value, and sophisticated built-in types. There should be no reason to deliberately expose an object’s data to the rest of the code because the language can enforce encapsulation and data hiding. Correct object-oriented design requires an object to encapsulate and hide its data, and to expose methods that are verbs acting on the object (not on individual properties of the object). The large majority of accessors are nouns — nothing more than pointless proxies for direct access to the object’s private data.

Others have pointed this out — see Allen Holub’s article “Why getter and setter methods are evil” from JavaWorld , for example. But the articles questioning the use of accessors are outnumbered by articles explaining how to write them. As with so many programming topics there is more argument about the details than about the big picture. Java and C# developers have IDEs that generate getters and setters automatically, implying that accessors are a good idea. Instead I think the IDE should yellow-flag every public member variable and accessor — they are warnings of bad design.

This article was prompted by a discussion with some of my own colleagues about how to write accessors in ActionScript (Flex). Unfortunately by the time we had that discussion the code we are working on was already full of accessors and public variables; introducing a standard for writing accessors would do nothing to eliminate the coupling created by the leaky objects. It would, however, insure that the code looked the same no matter who wrote it, a greatly overrated goal in my opinion. I was too polite to criticize the code’s design, and too realistic to expect it would be rewritten because it fails to meet even minimal standards of modularity or data hiding. Although enough of us know good code when we see it, correct software design is a custom more honored in the breach than the observance.

Here’s an example of arguing about the wrong thing. In a popular blog posting “Python is not Java” Phillip J. Eby explains how to write accessors the Pythonic way:

Getters and setters are evil. Evil, evil, I say! Python objects are not Java beans. Do not write getters and setters. This is what the ‘property’ built-in is for. And do not take that to mean that you should write getters and setters, and then wrap them in ‘property’. That means that until you prove that you need anything more than a simple attribute access, don’t write getters and setters . They are a waste of CPU time, but more important, they are a waste of programmer time. Not just for the people writing the code and tests, but for the people who have to read and understand them as well.

In Java, you have to use getters and setters because using public fields gives you no opportunity to go back and change your mind later to using getters and setters. So in Java, you might as well get the chore out of the way up front. In Python, this is silly, because you can start with a normal attribute and change your mind at any time, without affecting any clients of the class. So, don’t write getters and setters.

At least Java has refactoring IDEs and compiler type enforcement that make changing the type or meaning of a public member variable easy to find and fix. In Python those kinds of changes would manifest themselves in a series of runtime errors. This kind of article explains why Java and C# programmers (wrongly) conclude that Python needs static typing and a refactoring IDE. The correct inference is that getters and setters should be avoided because they break the encapsulation OOP offers . Avoiding them for performance or refactoring reasons misses the point.

Frequently I find that accessors are one of the side-effects of over-application of object oriented programming, especially when coding proceeds without a clear OO design. If your language insists that you implement everything as an object you have to devise workarounds for situations that don’t fit the object/message (noun/verb) OOP paradigm. Pretty soon a folklore grows around how to “correctly” implement accessors, and programmers focus more on implementing accessors the right way when they should be trying to eliminate the need for them in the first place. You can see the same thing with other OOP workarounds — the lore surrounding singletons is an even richer mine of how to do the wrong thing the right way.

Programmers who learned how to write getters and setters — especially if their IDE wrote the code for them — transfer that baggage to new languages they learn. That’s why there is no shortage of articles debating how to write accessors in languages that shouldn’t need them, e.g. Python, JavaScript, Ruby.

I’ve written hundreds of thousands of lines of code in my career, much of it in object-oriented languages, and I have rarely needed to expose a member variable or write an accessor. When I have it’s been to fit in with a code base that is already full of exposed data and accessors; in code like that, correctly designed object-oriented code is a square peg because none of the other classes hide their data or act on other objects through messages.

Trying to stop the proliferation of accessors is futile, but you can stop using them yourself. In the same way that writers try to eliminate passive voice and weak verbs from their writing, programmers can try to avoid getters and setters as much as practical. And when you see code with rampant getters and setters or public member variables you can recognize it as the mess it probably is.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Doing it wrong: getters and setters

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址