Anda di halaman 1dari 25

Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

!
NEWS
Building user interfaces for object-oriented systems, Part
1
What is an object? The theory behind building object-oriented user interfaces

By Allen Holub
JavaWorld |
JUL 1, 1999 1:00 AM PT

This month, I had intended to leap directly into the implementation of an object-
oriented user-interface (OOUI) implementation framework. Looking over what I was
writing, however, I came to the realization that there was no point in talking about
OOUI architecture and implementation without first explaining why such applications
have particular needs and must be implemented in certain ways. In other words, it
seemed like a good idea to start out with the big picture before zooming into the
details.

"Build user interfaces for object-oriented systems": Read the whole series!

Part 1. What is an object? The theory behind building object-oriented user


interfaces

Part 2. The visual-proxy architecture

Part 3. The incredible transmogrifying widget

Part 4. Menu negotiation

Part 5. Useful stuff

Part 6. An RPN-calculator application demonstrates object-oriented UI principles

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 1 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

I've actually written about this sort of stuff before, but not for JavaWorld, and the
articles I've written now are out of date, so I thought I'd take another stab at the
problem of describing object-oriented systems from the UI designer's point of view.
Hopefully, by the time I'm done you'll understand in general terms how a UI in an
object-oriented system has to work. I'll also endeavor to clarify why not one of the
RAD tools on the market today (Visual Café, Visual Age for Java, Visual J++, JBuilder --
you name it) is usable if your final goal is a well-crafted object-oriented system.

This month's article, then, is a primer on objects. It describes what an object is (or
what it should be in a well-constructed system) and how objects should interact with
one another at runtime. We'll also see how object-oriented systems, by nature, have
UI-design requirements that simply don't come up in procedural systems, so are rarely
implemented correctly by procedural programmers who are moving into an object-
oriented environment. In subsequent articles, I intend to apply these principles to real
code so that you can see how it all works. Next month, for example, I'll start looking
at a forms-based I/O system that works well in an object-oriented environment. This
article is a bit on the long side, but the concepts are essential, and I want to be as
thorough as possible in my coverage.

Everything you know is wrong! Key concepts of


object-oriented design
Bjarne Stroustrup, the inventor of C++, once characterized object-oriented
programming as "buzzword-oriented programming," and certainly one of the most
abused (or at least misunderstood) buzzwords in the pack is object itself. Since the
idea of the object is so central, a full discussion of what objects actually are is
essential to understanding object-oriented systems and their needs, particularly from
the perspective of the user interface.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 2 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

First of all, think of an object-oriented system as a bunch of intelligent animals (the


objects) inside your machine talking to each other by sending messages back and
forth. Think object. Classes are irrelevant -- they're just a convenience provided for the
compiler. The animals/objects that comprise our system can be classified together if
they have similar characteristics (if they can handle the same messages as other
objects in the class, for example), but what you have at runtime is a bunch of objects,
not classes -- animals, not their descriptions. What we programmers call classes are
really classes of objects. That is, a set of objects are of the same class if they have the
same properties. This usage is just English, and is really the correct way to think
about things. We're doing object-oriented design, not class-based design.
" Sign In | Register
The prime directive of object-oriented design is data abstraction. This is the CIA, need-
to-know-basis school of program design. All information is hidden. A given object
doesn't have any idea of what the innards of other objects look like, any more than
you might know what your spouse's gall bladder looks like. (In the case of both the
object and the gall bladder, you really don't want to know, either.)

So what, exactly, is an object?

You may have read in a book somewhere that an object is a datastructure of some
sort combined with a set of functions, called methods, that manipulate that
datastructure. Balderdash! Poppycock! First and foremost, an object is a collection of
capabilities. An object is defined by what it can do, not by how it does it -- and the
data is part of "how it does it." In practical terms, this means that an object is defined
by the messages it can receive and send; the methods that handle these messages
comprise the object's sole interface to the outer world. The emphasis must be on
what an object can do -- what capabilities it has -- not on how those capabilities are
implemented. The data is irrelevant. Most object-oriented designers will spend weeks,
if not months, in design before they even think about the data component of an
object. Of course, most objects will require some data in order to implement their
capabilities, but the make-up of that data is -- or at least should be -- irrelevant.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 3 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

I'll explain the whys and wherefors in a moment, but here are some rules of thumb
that you can apply to see if you're really looking at an object-oriented system:

1. All data is private. Period. (This rule applies to all implementation details, not
just the data.)

2. get and set functions are evil. (They're just elaborate ways to make the data
public.)

3. Never ask an object for the information you need to do something; rather, ask
the object that has the information to do the work for you.

4. It must be possible to make any change to the way an object is implemented, no


matter how significant that change may be, by modifying the single class that
defines that object.

5. All objects must provide their own UI.

If the system doesn't follow these rules, it isn't object-oriented. It's that simple. That's
not to say non-object-oriented systems are bad; there are many perfectly good
procedural systems in the world. Nonetheless, not exposing data is a fundamental
principle of object-oriented systems. If you violate your principles, you're nothing, and
the same goes for object-oriented systems. If a system violates object-oriented
principles, it isn't object-oriented; it's some sort of weird hybrid that you may or may
not ever get to work right.

Academic purity vs. in-the-trenches know-how

I should say that although the foregoing attitude might sound extreme, my ideas
don't stem from some academic notion of purity; rather, every time I've strayed from
the straight and narrow in my own work, I've found myself back in the code fixing it a
month or two later. All of this do-it-wrong-then-go-back-and-fix-it work just started

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 4 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

taking up too much time. It turned out to be easier to just do it right to begin with. My
notions, then, are based on practical experience gathered while putting together
working systems, and a desire to put those systems together as quickly as possible.

Don't be fooled, by the way, by products billed as "object-based" or by claims that


"there are lots of ways to define an object." Translate this sort of marketing hype as
follows: "Our product isn't really object-oriented -- we know that, but you probably
don't, and your manager (who's making the purchase decision) almost certainly
doesn't -- so we'll throw up a smoke screen and hope nobody notices." In the case of
Microsoft, it has simply redefined object-oriented to mean something that fits with its
product line. Visual Basic, for example, isn't in the least bit object-oriented. Neither is
Microsoft Foundation Classes (MFC) or most of the other Microsoft technology that
claims to be object-oriented. (How many Microsoft programmers does it take to screw
in a light bulb? None. Let's define darkness as the new industry standard.)

All the rules in the rule-of-thumb list above essentially say the same thing -- that the
inner state of an object must be hidden. In fact, the last rule in the list ("All objects
must provide their own UI") really just follows from the others. If access to the inner
state of an object is impossible, then the UI, which by necessity must access the state
information, must be created by the object whose state is being displayed. The
remainder of this article, as well as the columns of the next few months, will explain
how you can make this work.

Procedural vs. object-oriented systems


The main reason to heed the rules in the previous section is that they make your code
easier to maintain, because all the changes that typically need to be done to fix a
problem or add a feature tend to be concentrated in one place. Don't confuse ease of
maintenance with lack of complexity, by the way. Object-oriented systems are usually
more complex than procedural systems but are easier to maintain. The idea is to
organize the inevitable complexity inherent in real computer programs, not to

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 5 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

eliminate it. Object-oriented designers, as a class, consider the elimination of


complexity to be an impossible goal. They strive to organize the inherent complexity
of a complex system in such a way that the system is manageable. If anything, good
object-oriented systems are more complex than procedural ones, but in such systems
the program is better organized and thus easier to maintain.

Compare and contrast: An example

Consider a system designed to get names from users. You might be tempted to use a
TextField from which you extract a String, but that just won't work in a robust
application. What if the system needs to run in China? (Unicode comes nowhere near
representing all the idiographs that comprise written Chinese.) What if a user wants
to enter a name using a pen (or speech recognition) rather than a keyboard? What if
the database you're using to store the names can't store Unicode? What if you need
to change the program a year from now to add employee IDs everywhere names are
entered or displayed? In a procedural system, the solutions you come up with to
answer these questions usually highlight enormous maintenance problems inherent
to these systems. There's just no easy way to solve even the smallest problem, and a
vast effort is often required to make simple changes.

An object-oriented solution tries to encapsulate those things that are likely to change
in such a way that a change to one part of the program won't impact the rest of the
program at all. For example, an object-oriented solution to the problems I just
discussed requires a Name class, objects of which know how to both display and
initialize themselves. You would display the name by saying "display yourself over
there," passing in a Graphics object, or perhaps a Container to which the name
could drop in a JPanel that displayed the name. You would create a UI for a name by
telling an empty Name object to "initialize yourself using this piece of this window."
The Name object might choose to create a TextField for this purpose, but that's its
business. You, as a programmer, simply don't care how the name goes about

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 6 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)40 PM

initializing itself, as long as it is initialized. (The implementation might not create a


UI at all -- it might get the initial value by getting the required information from a
database or from across a network.)

Non-object-oriented approach #1: Model-View-Controller

Contrast the approach in the example above with the way a UI generated by a system
like Visual Café (or J++, or VisualAge, or JBuilder, or any of the rest) might work. On the
output side, a Frame class would extract data from a set of objects and render that
data on its client window. On the input side, a Frame might extract data from a bunch
of underlying widgets (or controls, or JavaBeans, or whatever you want to call them)
and then pass that data into the objects that comprise the logical model by calling a
bunch of "set" functions. This architecture is known as Model-View-Controller (MVC).
The widgets comprise the "view"; the Frame is the "controller"; and the underlying
system is the "model." MVC is okay for implementing little things like buttons, but it
fails miserably as an application-level architecture.

This extract-data-then-shove-it-elsewhere approach requires you to know way too


much about how the model-level objects are implemented. A system based on that
approach cannot be called object-oriented: there's just too much data flowing around
for the system to be maintainable. Unfortunately, many programmers mimic the MVC
architecture in their own hand-built code, so this non-object-oriented design is
endemic in some programs.

Non-object-oriented approach #2: Rapid application development

Page 1 of 4 ▻

Copyright © 2018 IDG Communications, Inc.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html Page 7 of 7
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)41 PM

#
NEWS
Building user interfaces for object-oriented systems, Part
1
What is an object? The theory behind building object-oriented user interfaces

By Allen Holub
JavaWorld |
JUL 1, 1999 1:00 AM PT

◅ Page 2 of 4 ▻

Rather than take my word for it, let's explore a few of the maintenance problems that
arise when you try to develop a significant program using the MVC architecture. In the
simple example above, you're tasked with adding an employee ID to every name in
every screen that displays employee names. In the RAD-style architecture, you'll have
to modify every one of these screens by hand, modifying or adding widgets to
accomodate the new ID field. You'll also have to add facilities to the Employee class
to be able to set the ID. And you'll have to examine every class that uses an Employee
to ensure that the ID hasn't broken anything. For example, comparison of two
Employee objects to see if they're equal must now use the ID, so you now have to
modify all this code. If you had simply encapsulated the identity into a Name class,
none of this work would be necessary. The Name objects would simply display
themselves in the new way. Two Name objects would now compare themselves using
the ID information; your code that called fred.compareTo(ginger) or
fred.equals(ginger) wouldn't have to change at all.

You can't even automate the update-the-code process, because all that WYSIWYG
functionality (that's so often touted in marketing buzz) hides the code-generation
process to the extent that it's impossible to modify machine-generated code safely. In

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=2 Page 1 of 3
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)41 PM

any event, if you automatically modify machine-generated code, your modifications


will be blown away the next time somebody uses the visual tool. Even if you don't
use the tool again, modifying machine-generated code is always risky, since most of
the RAD tools are very picky about what this code looks like, and if you do something
unexpected in your modifications, the RAD tool is likely to become so confused that it
will refuse to do anything at all the next time you do need to use it. Moreover, this
machine-generated code is often miserable stuff, created with little thought given to
efficiency, compactness, readability, and other important issues.

The real abomination in the RAD-style architecture is the "data-bound grid control," a
table-like widget that effectively encapsulates the SQL that's needed to fill its cells
from a database. What happens when the underlying data dictionary changes? All this
embedded SQL is rendered meaningless. You'll have to search out every screen in the
system that has a data-bound control and change that screen using a visual tool.
Going to a "three-tier" system -- where the UI layer talks to a layer that encapsulates
the SQL, which in turn talks to the database -- does nothing but make the problem
worse, since the code you have to modify has been distributed out into more places.
And in any event, if the middle tier is made of machine-generated code (usually the
case), its very existence is of little use from a maintenance point of view.

All this modifying-every-screen-by-hand business is way too much work for me. Any
time savings you may have gained by using the RAD tool to produce the initial code
are more than lost as soon as the code hits maintenance.

The appeal of these systems often lies in familiarity. They help you program in an
unfamiliar object-oriented language using a familiar procedural mindset. This sort of
$
I-can-program-FORTRAN-in-any-language mindset, however, precludes SignyourInability
| Register
to
leverage the real maintenance benefits of object-oriented systems. I personally feel
that there's absolutely no reason to use Java (or C++) unless you are indeed
implementing an object-oriented design. C++ in particular has so many problems that

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=2 Page 2 of 3
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)41 PM

it's not worth messing with if you aren't going to take advantage of its strengths, and
even Java isn't the height of simplicity -- it's simple only when compared to C++.
You're better off just using C if you want to write procedural systems.

On the other hand, if you are doing an object-oriented design, a language designed to
implement object-oriented systems (like Java) can make the implementation
dramatically easier. Many C programmers try to program in Java as if they were
programming in C, however, implementing procedural systems in Java rather than
object-oriented systems -- in other words, writing really awful code. This practice is
really encouraged by the language, which unfortunately mimics much of the syntax of
C and C++, including flaws like the messed-up precedence of bitwise operators. Java
mitigates the situation a bit because it's more of a "pure" object-oriented language
than C++. It is therefore harder, though not impossible, to abuse. (A determined
individual can write garbage code in any language.)

◅ Page 2 of 4 ▻

Copyright © 2018 IDG Communications, Inc.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=2 Page 3 of 3
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

#
"
Sign In | Register

NEWS
Building user interfaces for object-oriented systems, Part
1
What is an object? The theory behind building object-oriented user interfaces
By Allen Holub
JavaWorld |
JUL 1, 1999 1:00 AM PT

◅ Page 4 of 4

The well-crafted object-oriented system


Because the object-oriented way of looking at things is both essential and unfamiliar,
let's look at a more involved example of both the wrong way and the right way to put
together a system from the perspective of an object-oriented designer. I'll use an ATM
machine for this example (as do many books), not because any of us will be
implementing ATMs, but because an ATM is a good analog for both object-oriented
and client/server architectures. Look at the central bank computer as a server object
and the ATM as a client object.

A procedural solution

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 1 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

Most procedural database programmers would look at the server as a repository of


data and the client as a requester of that data. Such a programmer might approach
the problem of an ATM transaction as follows:

1. The user walks up to a machine, inserts the card, and punches in his or her PIN.

2. The ATM formulates a query of the form "give me the PIN associated with this
card," sends the query to the database, and verifies that the returned value
matches the one provided by the user. The ATM sends the PIN to the server as a
string -- part of the SQL query -- but the returned number is stored in a 16-bit
int to make the comparison easier.

3. The user requests a withdrawal.

4. The ATM formulates another query, this time: "give me the account balance." It
stores the returned balance in a 32-bit float.

5. If the balance is large enough, the machine dispenses the cash, and then posts
an "update the balance for this user" to the server.

So what's wrong with this picture? Let's start with the returned balance. What
happens when Bill Gates walks into our bank wanting to open a non-interest-bearing
checking account and put all his money in it? We really don't want to send him away,
but the last time we looked, Bill was worth about 87.94 gigabucks (see Resources).
Unfortunately, the 32-bit float we're using for the account balance can represent at
most 20 megabucks (4 gigabucks, divided by 2 for the sign bit, divided by 100 for the
cents). Similarly, the 16-bit int used for the PIN can hold at most four decimal digits.
What if Bill wants to use "GATES" (five digits) for his PIN? The final issue is that the
SQL queries are formulated by the ATM. If the underlying data dictionary changes (if
the name of a field changes, for example), the SQL queries won't work any more.

The procedural solution to all these problems is to change the ROMs in every ATM in
the world (since there's no telling which one Bill will use) to use 64-bit doubles
instead of 32-bit floats to hold account balances and to 32-bit longs to hold five-digit

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 2 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

PINs. That's an enormous maintenance problem, of course.

Stepping into the real world for a moment, the cost of software deployment is one of
the largest line-items on an IT department's budget. One of the appeals of Java (and
the NC architecture, which is still alive and well) in an enterprise-level company is
that, by eliminating deployment costs, you can save hundreds of millions of dollars
every year. The client/sever equivalent of "swapping all the ROMs" -- deploying new
versions of the client-side applications -- is a big deal. Similar maintenance problems
exist inside most procedural programs, even those that don't use databases. Change
definitions of a few central data types or global variables (that is, the program's
equivalent of the data dictionary), and virtually every subroutine in the program
might have to be rewritten. It's exactly this sort of maintenance nightmare that
object-oriented design hopes to solve.

An object-oriented solution

To see how an object-oriented point of view can solve the problems I've just recited,
let's recast the earlier problem in an object-oriented way, by looking at the system as
a set of cooperating objects that have certain capabilities. The first step in any object-
oriented design is to formulate a problem statement, which presents the problem
we're trying to solve entirely in what's called the problem domain. In the current
situation, the problem domain is banking. A problem statement describes a problem,
not a computer program. I might describe the current problem as follows:

A customer walks into a bank, gets a withdrawal slip from the teller, and fills it out.
The customer then returns to the teller, identifies himself, and hands the teller the
withdrawal slip. (The teller verifies that the customer is who he says he his by
consulting the bank records.) The teller then obtains an authorization from a bank
officer and dispenses the money to the customer.

Armed with this simple problem statement, we can identify a few potential key
abstractions (classes) and their associated operations. I'll use Ward Cunningham's CRC-
Card format (see Resources for more information on CRC cards):

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 3 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

Class Responsibility Collaborates with

Bank Creates withdrawal slips; verifies that customers are who Teller: requests
records they say they are empty withdrawal
slip

Bank Authorizes withdrawals Teller: requests


officer authorization

Withdrawal Records the amount of money requested by the teller Bank records:
slip creates it

Bank officer:
authorizes the
withdrawal

Teller: presents it to
customer

Teller Gets withdrawal slips from the bank records and routes the Bank records:
withdrawal slip to the bank officer for authorization creates withdrawal
slips

Bank officer:
authorizes
transactions

The server, in this model, is really the bank officer, whose main role is to authorize
transactions. The Bank, which is properly a server-side object as well, creates empty
deposit slips when asked. The client side is represented by the Teller object, whose
main role is to get a deposit slip from the Bank and pass it on. Interestingly, the
customer (Bill) is external to the system, so he doesn't show up in the model. (Banks
certainly have customers, but the customer isn't an attribute of the bank any more
than the janitorial service is part of the bank. The customer's accounts could be
attributes, certainly, but not the actual customers. You, for example, do not define
yourself as a piece of your bank.)

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 4 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

An object-oriented ATM system just models the earlier problem statement. Here's the
message flow:

1. Bill walks up to an ATM, presents his card and PIN, and requests a withdrawal.

2. The Teller object asks the server-side Bank_records object, "Is the person
with this card and this PIN legit?"

3. The Bank_records object comes back with "yes" or "no."

4. The Teller object asks the Bank_records object for an empty


Withdrawal_slip. (This object will be an instance of some class that
implements the Withdrawal_slip interface, and will be passed from the
Bank_records object to the Teller object by value (using RMI). That's
important. All the Teller knows about the object is the interface it implements
-- the implementation (the class file) comes across the wire along with the
object itself, so the Teller has no way of determining how the object will
actually process the messages sent to it. This abstraction is a good thing
because it lets us change the way the Withdrawal_slip object works without
having to change the Teller definition.)

5. The Teller object tells the Withdrawal_slip object to display a user interface.
(The object complies by rendering a UI on the ATM screen using AWT.)

6. Bill fills in the withdrawal slip.

7. The Teller object notices that the initialize-yourself operation is complete


(perhaps by monitoring the OK key), and passes the filled-out Withdrawal_slip
object to the server-side Bank_officer object (again by value, using RMI) as an
argument to the message: "Am I authorized to dispense this much money?"

8. The server-side Bank_officer object comes back with "yes" or "no."

9. If the answer is yes, the ATM dispenses the money. (For the sake of simplicity, I
won't go into how that happens.)

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 5 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

Of course, this isn't the only (or even the ideal) way to do things, but the example gets
the idea across -- bear with me.

The main thing to notice in this second protocol is that all knowledge of how a
balance or PIN is stored, how the server decides whether or not it's okay to dispense
money, and so forth, is hidden inside the various objects. This is possible because the
server is now an object that implements the "authorization" capability. Rather than
requesting the data that we need to authorize a transaction, the system asks the
(server-side) Bank_officer object (which has the data) to do the work for us. No data
(account balances or PINs) is being shipped to the ATM, so there's no need to change
the ATM when the server code changes. Also note that the Teller object isn't even
aware of how the money is specified. That is, the requested withdrawal amount is
encapsulated entirely within the Withdrawal_slip object. Consequently, a server-
side change in the way money is represented is entirely transparent to the client-side
Teller. And, most importantly, the bank's maintenance manager is happily sleeping it
off in the back office instead of running around changing ROMs. If only ATMs had
been written this way in Europe, translation to the euro would have been a simple
matter of changing the definition of the Withdrawal_slip (or Money) class on the
server side. Subsequent requests for a Withdrawal_slip from an ATM would yield a
euro-enabled version in reply.

Working with legacy systems


Another important issue is the "objectification" of legacy systems. In general, the
differences in organization between procedural and legacy systems is so extreme that
the vast majority of the code can't be salvaged. You're in pretty good shape if your
procedural system can be modularized into subsystems that can talk to one another
over a well-defined interface. Each of these subsystems can be viewed as a "facade"
object, and the subsystems can be translated to an object-oriented implementation
independently of one another. Most legacy systems are not so well organized,
however, and the translation can't even begin until you impose a modular
https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 6 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

organization at the procedural level. Your best bet is to design a new system from
scratch, and then figure out how to salvage as much of the existing code as possible
while implementing the new system. It's impossible to transform a procedural system
into an object-oriented system without a complete object-oriented design to show
you the way.

One of the most common problems that arise when making this translation is a
misinformed attempt to turn an existing struct definition into a class by making the
data private and then providing a get and set function for each field. This isn't
object-orientated programming -- it's just a very complicated way to access a field
that could be more easily accessed with a dot. In an object-oriented system, the data
wouldn't be accessed at all by nonmembers of the class. Rather, messages sent to an
object would request that the object exercise some capability, and the message
handler might use the data members of the class to do its job. Remember, structs and
classes are very different at the design level. A struct is a collection of data, a class is
a collection of capabilities.

A failed attempt to translate a legacy system

I saw a good example of this problem: a human-resources package that the


programmers were attempting to translate to be object-oriented. They took an
existing employee record (a C struct) and tried to transmogrify it into an Employee
class by making the fields private and providing get() and set() methods for each
field. One problem is that an Employee class will almost certainly have a salary
attribute, and, unfortunately, the original employee record had a salary field, so the
programmers equated the two. An attribute isn't the same as a field, however. An
attribute is a defining characteristic of an object. A salary serves to differentiate an
employee from a generic "person," for example. Without the salary, there would be no
difference between an employee and a person. Moreover, an attribute doesn't
necessarily map to a field in the class. The salary might be stored in an external
database, for example, with the Employee storing only the information needed to

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 7 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

retrieve the attribute from the database. If the Employee does store the salary
internally, it might be stored in a float, a double, a binary-coded-decimal array, a string
-- there's no telling. What, then, could a get_salary() function return? One of the
main tenets of object-oriented design is that it should be possible to radically modify
the private components of a class definition without affecting the users of the class
at all. The salary might be a float today, but there's no guarantee that it will stay that
way. Similarly, the matching get_salary() method might return a float today, but
what if the internal representation changed in such a way that a float wouldn't work
anymore? Say, for example, you needed to return an object of type Money that worked
like a float but handled the round-off-error-on-pennies problem. Letting the function
continue to return a float while using the Money class internally would defeat the
purpose of the Money class. Changing the function's return value would break every
subroutine that called the function.

It's exactly this change-induced ripple effect that object-oriented techniques are
meant to avoid.

The programmers of this system should have decided up front what capabilities to
give the Employee object -- what it could do, not what fields it had. Put another way,
you should never access an attribute directly; rather, you should ask the object to do
something with its attributes for you. In the case of the Employee object, there
should be no message of the form "give me your salary." You shouldn't extract the
attribute from an object in order to do something with it (like draw it in a window).
Rather, you should tell the object itself to do the operation ("print your salary in this
window"). The same reasoning would apply to a name -- not "give me your name," but
"draw your name here." This means that the way the attribute is stored inside the
object is utterly irrelevant. And as long as the salary is printed, I don't care how it's
stored.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 8 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

Though the foregoing process is the preferred way of doing things, you do sometimes
need to extract an attribute from an object. The salary might be needed by a
Payroll_department class to generate a paycheck, for example, and it might not be
appropriate for an Employee object to control the amount of its own paycheck. There
are several solutions to this problem, probably the best would be for the
Payroll_department class to ask the Employee for its salary. The salary should be
encapsulated in a Salary or Money object, and the Salary object should implement
all the capabilities needed to compute a paycheck (such as "divide yourself by,"
"subtract this from yourself," and of course, "draw yourself in this window"). This way,
the representation of the salary is still hidden. The returned Salary object should, of
course, be a constant. You don't want a Payroll_department to be able to modify a
salary, and you don't want the exposed salary to be different from the one stored in
the Employee.

This sort of encapsulation should really be used at every level of the system, even for
such basic things as strings. A String class really shouldn't expose any information
about how the characters are stored internally. In Java, the presence of a getBytes()
method in the String is a design flaw. All the operations you need for strings should
be implemented as methods of the String class. So it shouldn't be "give me your
buffer so I can do something to it," but "do something to yourself." This way, you're
completely isolated from the way that the String objects store characters internally.
The characters could be stored in a char array, but a String could just as easily
represent itself internally using some sort of multibyte coding, or even a sequence of
images, or some form that no one has thought of yet. If the internal representation is
never exported, the implementation of the internal representation is irrelevant to the
user of the String.

This structure implies, of course, that there are no functions in the system that take
byte[] (or even char[]) arguments; all strings must be String objects. And that's
another aspect of object-oriented systems: they tend to be all-or-nothing. Everything

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 9 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

must be a String object, there's no way to mix string objects with arrays of char and
get the maintenance advantage promised by object orientation. That's one of the
reasons that the translation of legacy systems to object-oriented systems is so
difficult.

There are two ways to initialize a string in a GUI. You could pass the String object
the message: "Initialize yourself dynamically, using this piece of this window." The
String would then create the JTextField needed for that purpose and install it on
the window. Or you could say "Give me back some Component object that will be used
for initialization." I think of this Component object as a visual proxy for some hidden
field of the String. I can position it on the screen, size it, enable and disable it, and
so on. The characters the user types into the proxy flow directly into the String
object that created it, however. (The String object sets itself up as a listener to the
TextField object used as a proxy before it returns the proxy to the requester.) The
Frame that holds the proxy isn't aware that any activity has occurred at all. I'll discuss
this visual-proxy architecture in more depth next month.

The point of this organization is that you can now make changes to the structure of
an object without affecting any of the code that uses the object -- and that's one of
the main strengths of an object-oriented approach. Changes made in one place are
highly localized (as are bugs). This localization not only makes code easier to
maintain, it makes it easier to debug and to write initially.

The obvious 'object'ions (so to speak)


Whenever I present the foregoing, I always get a few knee-jerk responses from the
hard-core procedural element in the crowd, so let me address a few of the more
common gripes up front.

Gripe #1. Graphical functionality within an object

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 10 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

One of the main objections I've heard to the object-oriented approach to UI


development is: "Horrors! Then there's graphical functionality inside model-level
objects." Well, not exactly, but even if there were, why is that a problem? The next few
columns will describe in detail how to actually separate the graphical functionality
from the model in an object-oriented way using variants on the visual-proxy pattern I
just introduced to concentrate the UI mechanisms into well-defined places.

For now, though, chew on the following. Traditional procedural programs attempted
to isolate the underlying graphical system from the logical parts of the program (the
model) by concentrating all system-dependent code in one subsystem. The goal was
to be able to change graphical environments, for example, by swapping out a single
subsystem. Historically, this approach has failed miserably in the procedural world
because myriad tentacles tend to go from the UI side to the model side. In other
words, the GUI is concentrated into a single shared library or DLL, but it isn't isolated
from the rest of the system in any meaningful way. Every time the model changes, so
does the UI, and vice versa. Not only have you solved nothing by "isolating" the GUI,
you've introduced a considerable amount of unnecessary complexity, and the
concomitant maintenance difficulties, into the program.

Just because we've historically done things in a particular way doesn't mean it is the
best way to do things; otherwise, we'd all still be programming in assembly language.
Conventional wisdom is rarely correct. I want proof. In any event, the architecture I'm
advocating is isolated from the underlying system, in spite of the fact that there's
some model-side rendering going on. You aren't writing directly to the OS; you're
writing to AWT (or Swing), which is after all the Abstract Windowing Toolkit. That is, by
writing to an abstraction layer, you have isolated yourself from the graphical
environment. If you change graphical environments, all the necessary changes are
concentrated in one place: inside AWT and Swing.

Gripe #2. Different views into the same object

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 11 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

The other bugaboo that I want to put to death is the notion of different views into
the same object, usually characterized by the question: "Suppose you need to display
this data as a pie chart over here and a grid over there? How can you do this if the
object displays itself?"

Now let's get real. How often in your work has this problem actually come up? In
talking about object-oriented architectures for the user interface to many hundreds, if
not thousands, of programmers, only two or three have ever raised their hands when I
asked that question. If I need a generic presentation program that has no notion of
what the data means, I'll go buy a copy of Excel or Quattro Pro. I won't write a
program. The fact is that data has meaning -- it's not just an arbitrary collection of
numbers. For a given set of data, I would argue that that there is only one "best" way
to represent it for a specific problem domain. If there's no "best" way, then just settle
on one "good" way. This degree of flexibility is rarely required. In any event, it is
possible for an object to display itself in different ways without violating its integrity.
I'll talk about how to do just that in a forthcoming column.

The next question is usually: "What about JavaBeans, they use get and set functions
all over the place." First, these get and set functions are intended to provide an
interface between the bean and its (compile-time) design tool. In an object-oriented
system, you'll never call one of these get or set methods from your own code (or at
least you shouldn't). In an ideal world, Java would have a bean access privilege that
would work like private but would permit access by the classes that comprise a
BeanBox tool as well. In any event, this get/set strategy was provided in an (I think
misguided) attempt to make programming beans "easy" -- that is, easy for procedural
programmers who don't know object-oriented programming. Fortunately, the
JavaBeans spec does provide a true object-oriented mechanism for interacting with
the design-time tool: the bean Customizer, which creates a complete UI in response
to an "initialize yourself" request. A tool-generated property sheet isn't used if you

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 12 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

have a Customizer. If you're serious about object-oriented programming, then your


beans should all initialize themselves with Customizers, and you shouldn't use the
get/set strategy at all.

Most 'RAD' tools don't make things go faster


Finally, I want to shoot off at the mouth a bit about the whole notion of "rapid"
application development tools. If you haven't figured it out by now, I'm not much of a
fan of the current crop of programs that go by that name. The original RAD systems
weren't wowie-zowie software programs; they were very structured design and
development processes. The way most developers work with the RAD tools is inimical
to fundamental notions of the RAD process. Real RAD always involves a lengthy and
thorough design process, for example. Today's typical RAD tool, on the other hand,
makes it almost impossible to do real design work, since they look at a system as a UI
with a few intelligent warts hanging off of it. There's no coherence to the resulting
code -- in many systems you can't even print a complete listing. Even if you do do a
complete design, most RAD tools provide you with no way of realizing it since they
force you into their notion of what the system should look like. In other words, you're
forced by the system into supporting the RAD tools' usually horrendous architecture.

So why are the RAD systems useless in producing object-oriented user interfaces?
The short answer is, because they all use the extract-data-then-shove-it-elsewhere
approach I discussed earlier. Any system whose design focuses on data flow, rather
than message passing, is fundamentally incorrect in the object-oriented model.

As a consequence, RAD tools deliver virtually none of their promise. That application
you throw together so quickly is going to take ten to twenty times more effort to
maintain than would hand-built code. To paraphrase Fred Brook's wonderful essay
"No Silver Bullet," well over half of the time you spend working on a project (on the
order of 70 percent) is spent thinking, and no tool, no matter how advanced, can think
for you. Consequently, even if a tool did everything except the thinking for you -- if it

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 13 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

wrote 100 percent of the code, wrote 100 percent of the documentation, did 100
percent of the testing, burned the CD-ROMs, put them in boxes, and mailed them to
your customers -- the best you could hope for would be a 30 percent improvement in
productivity. In order to do better than that, you have to change the way you think.

Conclusion
So, changing the way that you think -- in an applied sense --- will be the subject of
the next few articles. Rather than discussing object-oriented priniciples as an
academic exercise, we'll build a few UI tools using the principles I've discussed here.
The forms-based I/O package that we'll start on next month, for example, sets things
up so that the implementation of the model-side objects is completely hidden from
the display code. This way, you can radically change the way your forms look without
impacting the model, and you can radically change the implementation of the model
without impacting the forms-generation code. This sort of neat modularization in aid
of easy maintenance is what object-oriented design is all about. We'll also see,
however, that drag-and-drop tools will be of no help at all in building this object-
oriented system. On the flip-side, we'll also see that the code is simple enough to
construct by hand so that a drag-and-drop tool isn't all that necessary.

Allen Holub has been working in the computer industry since 1979. He is widely published in
magazines (Dr. Dobb's Journal, Programmers Journal, Byte, and MSJ, among others). He has seven
books to his credit, and is currently working on an eighth that will present the complete sources for a
Java compiler written in Java. After eight years as a C++ programmer, Allen abandoned C++ for Java in
early 1996. He now looks at C++ as a bad dream, the memory of which is mercifully fading. He's been
teaching programming (first C, then C++ and MFC, now object-oriented design and Java) both on his
own and for the University of California Berkeley Extension since 1982. Allen offers both public
classes and in-house training in Java and object-oriented design topics. He also does object-oriented
design consulting and contract Java programming. Get information, and contact Allen, via his Web
site http://www.holub.com.

Learn more about this topic

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 14 of 15
Building user interfaces for object-oriented systems, Part 1 | JavaWorld 12/02/18, 9)42 PM

The Bill Gates Personal Wealth Clock. Find out what Bill's really worth
http://www.webho.com/WealthClock (http://www.webho.com/WealthClock )
"No Sliver Bullet," The Mythical Man Month, Anniversary Edition, Frederick Brooks (Addison-Wesley, 1995)
http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201835959
(http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201835959)
The CRC Card Book, David Bellin and Susan Suchman Simone (Addison-Wesley, 1997)
http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201895358
(http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201895358)
C++ in Hypertext, Curtis Solohub. This online CS-1 textbook offers a pretty good description of object-
oriented-design techniques in general (and CRC cards in particular)
http://cs.nmhu.edu/personal/curtis/cs1htmlfiles/Cs1text.htm
(http://cs.nmhu.edu/personal/curtis/cs1htmlfiles/Cs1text.htm )

Follow everything from JavaWorld ! " # $ %

◅ Page 4 of 4

Copyright © 2018 IDG Communications, Inc.

https://www.javaworld.com/article/2076459/core-java/building-user-interfaces-for-object-oriented-systems--part-1.html?page=4 Page 15 of 15

Anda mungkin juga menyukai