分享
 
 
 

More on getters and setters

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

下面这篇文章是关于GETTER/SETTER方法

的一些讨论。老实说,作者从简单的问题说出的OO思想,让我受益匪浅,

开始让我重新审视自己对OO的理解,看来也很有必要补习补习OO的基础理论知识了。

More on getters and setters

Build user interfaces without getters and setters

Summary

--

Summary

Allen Holub's past Java Toolbox column, "Why Getter and Setter Methods Are Evil," discussed the downside of the getter/setter idiom. That article presented a design-level solution. (By keeping your design in the problem domain as long as possible and using dynamic modeling techniques like CRC (classes, responsibilities, collaboration) modeling, the getter/setter methods tend not to show up at all.) This article expands on the previous article by providing one of several possible programmatic solutions to the get/set-elimination problem. In particular, Allen demonstrates how to use the Gang of Four Builder design pattern to construct both Web-based and client-side user interfaces without exposing your object's implementation to the entire program. (2,800 words; January 2, 2004) --By Allen Holub

Page 1 of 3

t's a 25-year-old principle of object-oriented (OO) design that you shouldn't expose an object's implementation to any other classes in the program. The program is unnecessarily difficult to maintain when you expose implementation, primarily because changing an object that exposes its implementation mandates changes to all the classes that use the object.

Unfortunately, the getter/setter idiom that many programmers think of as object oriented violates this fundamental OO principle in spades. Consider the example of a Money class that has a getValue() method on it that returns the "value" in dollars. You will have code like the following all over your program:

double orderTotal;

Money amount = ...;

//...

orderTotal += amount.getValue(); // orderTotal must be in dollars

The problem with this approach is that the foregoing code makes a big assumption about how the Money class is implemented (that the "value" is stored in a double). Code that makes implementation assumptions breaks when the implementation changes. If, for example, you need to internationalize your application to support currencies other than dollars, then getValue() returns nothing meaningful. You could add a getCurrency(), but that would make all the code surrounding the getValue() call much more complicated, especially if you persist in using the getter/setter strategy to get the information you need to do the work. A typical (flawed) implementation might look like this:

Money amount = ...;

//...

value = amount.getValue();

currency = amount.getCurrency();

conversion = CurrencyTable.getConversionFactor( currency, USDOLLARS );

total += value * conversion;

//...

This change is too complicated to be handled by automated refactoring. Moreover, you would have to make these sorts of changes everywhere in your code.

The business-logic-level solution to this problem is to do the work in the object that has the information required to do the work. Instead of extracting the "value" to perform some external operation on it, you should have the Money class do all the money-related operations, including currency conversion. A properly structured object would handle the total like this:

Money total = ...;

Money amount = ...;

total.increaseBy( amount );

The add() method would figure out the currency of the operand, do any necessary currency conversion (which is, properly, an operation on money), and update the total. If you used this object-that-has-the-information-does-the-work strategy to begin with, the notion of currency could be added to the Money class without any changes required in the code that uses Money objects. That is, the work of refactoring a dollars-only to an international implementation would be concentrated in a single place: the Money class.

The problem

Most programmers have no difficulty grasping this concept at the business-logic level (though it can take some effort to consistently think that way). Problems start to emerge, however, when the user interface (UI) enters the picture. The problem is not that you can't apply techniques like the one I just described to build a UI, but that many programmers are locked into a getter/setter mentality when it comes to user interfaces. I blame this problem on fundamentally procedural code-construction tools like Visual Basic and its clones (including the Java UI builders) that force you into this procedural, getter/setter way of thinking.

(Digression: Some of you will balk at the previous statement and scream that VB is based on the hallowed Model-View-Controller (MVC) architecture, so is sacrosanct. Bear in mind that MVC was developed almost 30 years ago. In the early 1970s, the largest supercomputer was on par with today's desktops. Most machines (such as the DEC PDP-11) were 16-bit computers, with 64 KB of memory, and clock speeds measured in tens of megahertz. Your user interface was probably a stack of punched cards. If you were lucky enough to have a video terminal, then you may have been using an ASCII-based console input/output (I/O) system. We've learned a lot in the past 30 years. Even Java Swing had to replace MVC with a similar "separable-model" architecture, primarily because pure MVC doesn't sufficiently isolate the UI and domain-model layers.)

So, let's define the problem in a nutshell:

If an object may not expose implementation information (through get/set methods or by any other means), then it stands to reason that an object must somehow create its own user interface. That is, if the way that an object's attributes are represented is hidden from the rest of the program, then you can't extract those attributes in order to build a UI.

Note, by the way, that you're not hiding the fact that an attribute exists. (I'm defining attribute, here, as an essential characteristic of the object.) You know that an Employee must have a salary or wage attribute, otherwise it wouldn't be an Employee. (It would be a Person, a Volunteer, a Vagrant, or something else that doesn't have a salary.) What you don't know—or want to know—is how that salary is represented inside the object. It could be a double, a String, a scaled long, or binary-coded decimal. It might be a "synthetic" or "derived" attribute, which is computed at runtime (from a pay grade or job title, for example, or by fetching the value from a database). Though a get method can indeed hide some of this implementation detail, as we saw with the Money example, it can't hide enough.

So how does an object produce its own UI and remain maintainable? Only the most simplistic objects can support something like a displayYourself() method. Realistic objects must:

Display themselves in different formats (XML, SQL, comma-separated values, etc.).

Display different views of themselves (one view might display all the attributes; another might display only a subset of the attributes; and a third might present the attributes in a different way).

Display themselves in different environments (client side (JComponent) and served-to-client (HTML), for example) and handle both input and output in both environments.

Some of the readers of my previous getter/setter article leapt to the conclusion that I was advocating that you add methods to the object to cover all these possibilities, but that "solution" is obviously nonsensical. Not only is the resulting heavyweight object much too complicated, you'll have to constantly modify it to handle new UI requirements. Practically, an object just can't build all possible user interfaces for itself, if for no other reason than many of those UIs weren't even conceived when the class was created.

Next page >

Page 1 More on getters and setters

Page 2 Build a solution

Page 3 Consequences of refactoring the Context

See JavaWorld Talkback on the last page of this article to post your comments and see how fellow readers reacted.

Printer-friendly version | Mail this to a friend

Resources

Download this article's complete source code:

http://www.holub.com/publications/articles

"Why Getter and Setter Methods Are Evil," Allen Holub (JavaWorld, September 2003):

http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html

Builder is discussed on p. 97f of the Gang of Four book, Design Patterns, Eric Gamma, Richard Helm, Ralph Johnson, John Vlissides (Addison-Wesley Publishing Co., 1995; ISBN: 0201633612)

http://www.amazon.com/exec/obidos/ASIN/0201633612/alleiholuasso

David Geary's Java Design Patterns column about the Strategy pattern, "Strategy For Success" (JavaWorld, April 2002):

http://www.javaworld.com/javaworld/jw-04-2002/jw-0426-designpatterns.html

Another UI architecture that doesn't require get/set methods is described in Allen Holub's past article, "Build User Interfaces For Object-Oriented Systems, Part 2: The Visual-Proxy Architecture" (JavaWorld, September 1999):

http://www.javaworld.com/javaworld/jw-09-1999/jw-09-toolbox.html

Allen Holub's forthcoming book Holub on Patterns: Learning Design Patterns by Looking at Code (Apress, summer 2004) presents another example of using Builder for I/O, but in the context of importing and exporting database tables. In particular, all knowledge of the format used to store the data on the disk is encapsulated in the Builder rather than the database classes. This way the database can export tables to multiple formats, even ones that didn't exist when the classes were written.

Justin Kruger and David Dunning's spectacular article "Unskilled and Unaware of It: How Difficulties in Recognizing One's Own Incompetence Lead to Inflated Self-Assessments" goes a long way to explaining why concepts such as implementation encapsulation are so hard for procedural programmers to grasp. This article should be required reading for all computer programmers. Find it at:

http://www.apa.org/journals/psp/psp7761121.html

See all of Allen Holub's Java Toolbox columns:

http://www.javaworld.com/columns/jw-toolbox-index.shtml

View David Geary's Java Design Patterns columns:

http://www.javaworld.com/columns/jw-java-design-patterns-index.shtml

Browse the Design Patterns section of JavaWorld's Topical Index:

http://www.javaworld.com/channel_content/jw-patterns-index.shtml

Browse the User Interface Design section of JavaWorld's Topical Index:

http://www.javaworld.com/channel_content/jw-ui-index.shtml

Browse the Object-Oriented Design and Programming section of JavaWorld's Topical Index:

http://www.javaworld.com/channel_content/jw-oop-index.shtml

Visit the Programming Theory & Practice discussion:

http://www.javaworld.com/javaforums/postlist.php?Cat=&Board=TheoryPractice

Sign up for JavaWorld's free weekly newsletters:

http://www.javaworld.com/subscribe

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有