📄 tij303.htm
字号:
<p>But how do you get an object to do useful work for you? There must be a way to make a request of the object so that it will do something, such as complete a transaction, draw something on the screen, or turn on a switch. And each object can satisfy only certain requests. The requests you can make of an object are defined by its <i>interface,</i> and the type is what determines the interface. A simple example might be a representation of a light bulb: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_122" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><img src="TIJ304.png" alt="TIJ304.png" border="0" ><br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Light lt = <font color=#0000ff>new</font> Light();
lt.on();</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>The interface establishes <i>what</i> requests you can make for a particular object. However, there must be code somewhere to satisfy that request. This, along with the hidden data, comprises the <a name="Index53"></a><i>implementation</i>. From a procedural programming standpoint, it’s not that complicated. A type has a method associated with each possible request, and when you make a particular request to an object, that method is called. This process is usually summarized by saying that you “send a message” (make a request) to an object, and the object figures out what to do with that message (it executes code). <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_123" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Here, the name of the type/class is <b>Light</b>, the name of this particular <b>Light </b>object is <b>lt</b>,<b> </b>and the requests that you can make of a <b>Light</b> object are to turn it on, turn it off, make it brighter, or make it dimmer. You create a <b>Light </b>object by defining a “reference” (<b>lt</b>) for that object and calling <b>new</b> to request a new object of that type. To send a message to the object, you state the name of the object and connect it to the message request with a period (dot). From the standpoint of the user of a predefined class, that’s pretty much all there is to programming with objects. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_124" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The preceding diagram follows the format of the <a name="Index54"></a><a name="Index55"></a><i>Unified Modeling Language</i> (UML). Each class is represented by a box, with the type name in the top portion of the box, any data members that you care to describe in the middle portion of the box, and the <a name="Index56"></a><a name="Index57"></a><i>methods</i> (the functions that belong to this object, which receive any messages you send to that object) in the bottom portion of the box. Often, only the name of the class and the public methods are shown in UML design diagrams, so the middle portion is not shown. If you’re interested only in the class name, then the bottom portion doesn’t need to be shown, either. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_125" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545190"></a><a name="_Toc408018387"></a><a name="_Toc472654684"></a><a name="_Toc24775515"></a><a name="Heading1028"></a>An
object provides services</h2>
<p>While you’re trying to develop or understand a program design, one of the best ways to think about objects is as “service providers.” Your program itself will provide services to the user, and it will accomplish this by using the services offered by other objects. Your goal is to produce (or even better, locate in existing code libraries) a set of objects that provide the ideal services to solve your problem. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0437" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>A way to start doing this is to ask “if I could magically pull them out of a hat, what objects would solve my problem right away?” For example, suppose you are creating a bookkeeping program. You might imagine some objects that contain pre-defined bookkeeping input screens, another set of objects that perform bookkeeping calculations, and an object that handles printing of checks and invoices on all different kinds of printers. Maybe some of these objects already exist, and for the ones that don’t, what would they look like? What services would <i>those</i> objects provide, and what objects would <i>they</i> need to fulfill their obligations? If you keep doing this, you will eventually reach a point where you can say either “that object seems simple enough to sit down and write” or “I’m sure that object must exist already.” This is a reasonable way to decompose a problem into a set of objects. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0438" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Thinking of an object as a service provider has an additional benefit: it helps to improve the cohesiveness of the object. <i>High</i> <i>cohesion</i> is a fundamental quality of software design: It means that the various aspects of a software component (such as an object, although this could also apply to a method or a library of objects) “fit together” well. One problem people have when designing objects is cramming too much functionality into one object. For example, in your check printing module, you may decide you need an object that knows all about formatting and printing. You’ll probably discover that this is too much for one object, and that what you need is three or more objects. One object might be a catalog of all the possible check layouts, which can be queried for information about how to print a check. One object or set of objects could be a generic printing interface that knows all about different kinds of printers (but nothing about bookkeeping—this one is a candidate for buying rather than writing yourself). And a third object could use the services of the other two to accomplish the task. Thus, each object has a cohesive set of services it offers. In a good object-oriented design, each object does one thing well, but doesn’t try to do too much. As seen here, this not only allows the discovery of objects that might be purchased (the printer interface object), but it also produces the possibility of an object that might be reused somewhere else (the catalog of check layouts). <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0439" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Treating objects as service providers is a great simplifying tool, and it’s very useful not only during the design process, but also when someone else is trying to understand your code or reuse an object—if they can see the value of the object based on what service it provides, it makes it much easier to fit it into the design. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0440" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc24775516"></a><a name="Heading1033"></a>The hidden
implementation</h2>
<p>It is helpful to break up the playing field into <a name="Index58"></a><i>class creators</i> (those who create new data types) and <a name="Index59"></a><a name="Index60"></a><i>client programmers</i><sup><a name="fnB5" href="#fn5">[5]</a></sup> (the class consumers who use the data types in their applications). The goal of the client programmer is to collect a toolbox full of classes to use for rapid application development. The goal of the class creator is to build a class that exposes only what’s necessary to the client programmer and keeps everything else hidden. Why? Because if it’s hidden, the client programmer can’t access it, which means that the class creator can change the hidden portion at will without worrying about the impact on anyone else. The hidden portion usually represents the tender insides of an object that could easily be corrupted by a careless or uninformed client programmer, so hiding the implementation reduces program bugs. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_126" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The concept of implementation hiding cannot be overemphasized. In any relationship it’s important to have boundaries that are respected by all parties involved. When you create a library, you establish a relationship with the client<a name="Index62"></a><a name="Index63"></a><i> </i>programmer, who is also a programmer, but one who is putting together an application by using your library, possibly to build a bigger library. If all the members of a class are available to everyone, then the client programmer can do anything with that class and there’s no way to enforce rules. Even though you might really prefer that the client programmer not directly manipulate some of the members of your class, without access control there’s no way to prevent it. Everything’s naked to the world. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_128" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>So the first reason for access control is to keep client programmers’ hands off portions they shouldn’t touch—parts that are necessary for the internal operation of the data type but not part of the interface that users need in order to solve their particular problems. This is actually a service to users because they can easily see what’s important to them and what they can ignore. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_129" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The second reason for access control is to allow the library designer to change the internal workings of the class without worrying about how it will affect the client programmer. For example, you might implement a particular class in a simple fashion to ease development, and then later discover that you need to rewrite it in order to make it run faster. If the interface and implementation are clearly separated and protected, you can accomplish this easily. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_130" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p><a name="Index64"></a><a name="Index65"></a><a name="Index66"></a>Java uses three explicit keywords to set the boundaries in a class: <b>public</b>, <b>private</b>, and <b>protected</b>. Their use and meaning are quite straightforward. These <i>access specifiers</i> <a name="Index67"></a><a name="Index68"></a><a name="Index69"></a>determine who can use the definitions that follow. <b>public</b> <a name="Index70"></a>means the following element is available to everyone. The <b>private</b> <a name="Index71"></a>keyword, on the other hand, means that no one can access that element except you, the creator of the type, inside methods of that type. <b>private</b> is a brick wall between you and the client programmer. Someone who tries to access a <b>private</b> member will get a compile-time error. The <b>protected</b><a name="Index72"></a> keyword acts like <b>private</b>, with the exception that an inheriting class has access to <b>protected</b> members, but not <b>private</b> members. Inheritance will be introduced shortly. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_131" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Java also has a “default” access, which comes into play if you don’t use one of the aforementioned specifiers. This is usually called <i>package</i> <i>access</i> because classes can access the members of other classes in the same package, but outside of the package those same members appear to be <b>private</b>. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_132" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545191"></a><a name="_Toc408018388"></a><a name="_Toc472654685"></a><a name="_Toc24775517"></a><a name="Heading1041"></a>Reusing
the implementation</h2>
<p>Once a class has been created and tested, it should (ideally) represent a useful unit of code. It turns out that this reusability is not nearly so easy to achieve as many would hope; it takes experience and insight to produce a reusable object design. But once you have such a design, it begs to be reused. Code reuse is one of the greatest advantages that object-oriented programming languages provide. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_133" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p><a name="Index73"></a>The simplest way to reuse a class is to just use an object of that class directly, but you can also place an object of that class inside a new class. We call this “creating a member object.” Your new class can be made up of any number and type of other objects, in any combination that you need to achieve the functionality desired in your new class. Because you are composing a new class from existing classes, this concept is called <a name="Index74"></a><a name="Index75"></a><a name="Index76"></a><i>composition</i> (if the composition happens dynamically, it’s usually called <a name="Index77"></a><i>aggregation</i>). Composition is often referred to as a “has-a” relationship, as in “a car has an engine.” <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_134" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><a name="Index78"></a><img src="TIJ305.png" alt="TIJ305.png" border="0" ><br></p>
<p>(This UML diagram indicates composition with the filled diamond, which states there is one car. I will typically use a simpler form: just a line, without the diamond, to indicate an association.<a name="Index79"></a><sup><a name="fnB6" href="#fn6">[6]</a></sup>) <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_135" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Composition comes with a great deal of flexibility. The member objects of your new class are typically private, making them inaccessible to the client programmers who are using the class. This allows you to change those members without disturbing existing client code. You can also change the member objects at run time, to dynamically change the behavior of your program. Inheritance, which is described next, does not have this flexibility since the compiler must place compile-time restrictions on classes created with inheritance. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_136" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Because inheritance is so important in object-oriented programming it is often highly emphasized, and the new programmer can get the idea that inheritance should be used everywhere. This can result in awkward and overly complicated designs. Instead, you should first look to composition when creating new classes, since it is simpler and more flexible. If you take this approach, your designs will be cleaner. Once you’ve had some experience, it will be reasonably obvious when you need inheritance. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_137" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545192"></a><a name="_Toc408018389"></a><a name="_Toc472654686"></a><a name="_Toc24775518"></a><a name="Heading1049"></a>Inheritance:<br>reusing
the interface</h2>
<p>By itself, the idea of an object is a convenient tool. It allows you to package data and functionality together by <i>concept</i>, so you can represent an appropriate problem-space idea rather than being forced to use the idioms of the underlying machine. These concepts are expressed as fundamental units in the programming language by using the <a name="Index80"></a><b>class</b> keyword. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_138" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>It seems a pity, however, to go to all the trouble to create a class and then be forced to create a brand new one that might have similar functionality. It’s nicer if we can take the existing class, clone it, and then make additions and modifications to the clone. This is effectively what you get with <a name="Index81"></a><i>inheritance</i>, with the exception that if the original class (called the <i>base class</i> or <i>superclass </i>or <i>parent</i> <i>class</i>) is changed, the modified “clone” (called the <i>derived class </i>or <i>inherited class</i> or <i>subclass</i> or <i>child</i><b> </b><i>class</i>) also reflects those changes. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_139" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><img src="TIJ306.png" alt="TIJ306.png" border="0" ><br></p>
<p>(The arrow in this UML diagram points from the derived class to the base class. As you will see, there is commonly more than one derived class.) <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_140" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>A type does more than describe the constraints on a set of objects; it also has a relationship with other types. Two types can have characteristics and behaviors in common, but one type may contain more characteristics than another and may also handle more messages (or handle them differently). Inheritance expresses this similarity between types by using the concept of base types and derived types. A base type contains all of the characteristics and behaviors that are shared among the types derived from it. You create a base type to represent the core of your ideas about some objects in your system. From the base type, you derive other types to express the different ways that this core can be realized. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_141" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p><a name="Index82"></a><a name="Index83"></a><a name="Index84"></a><a name="Index85"></a>For example, a trash-recycling machine sorts pieces of trash. The base type is “trash,” and each piece of trash has a weight, a value, and so on, and can be shredded, melted, or decomposed. From this, more specific types of trash are derived that may have additional characteristics (a bottle has a color) or behaviors (an aluminum can may be crushed, a steel can is magnetic). In addition, some behaviors may be different (the value of paper depends on its type and condition). Using inheritance, you can build a type hierarchy that expresses the problem you’re trying to solve in terms of its types. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_142" title="Send BackTalk Comment">Feedback</a></font><br></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -