⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tij303.htm

📁 这也是我们java老师给我们的thinking in java的一些资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<p>A second example is the classic &#147;shape&#148; example, perhaps used in a computer-aided design system or game simulation. The base type is &#147;shape,&#148; and each shape has a size, a color, a position, and so on. Each shape can be drawn, erased, moved, colored, etc. From this, specific types of shapes are derived (inherited)&#151;circle, square, triangle, and so on &#151; each of which may have additional characteristics and behaviors. Certain shapes can be flipped, for example. Some behaviors may be different, such as when you want to calculate the area of a shape. The type hierarchy embodies both the similarities and differences between the shapes. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_143" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><a name="Index86"></a><img src="TIJ307.png" 	alt="TIJ307.png" border="0" ><br></p>
<p>Casting the solution in the same terms as the problem is tremendously beneficial because you don&#146;t need a lot of intermediate models to get from a description of the problem to a description of the solution. With objects, the type hierarchy is the primary model, so you go directly from the description of the system in the real world to the description of the system in code. Indeed, one of the difficulties people have with object-oriented design is that it&#146;s too simple to get from the beginning to the end. A mind trained to look for complex solutions can initially be stumped by this simplicity. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_144" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>When you inherit from an existing type, you create a new type. This new type contains not only all the members of the existing type (although the <b>private</b> ones are hidden away and inaccessible), but more importantly it duplicates the interface of the base class. That is, all the messages you can send to objects of the base class you can also send to objects of the derived class. Since we know the type of a class by the messages we can send to it, this means that the derived class <i>is the same type as the base class</i>. In the previous example, &#147;a circle is a shape.&#148; This type equivalence via inheritance is one of the fundamental gateways in understanding the meaning of object-oriented programming. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_145" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Since both the base class and derived class have the same fundamental interface, there must be some implementation to go along with that interface. That is, there must be some code to execute when an object receives a particular message. If you simply inherit a class and don&#146;t do anything else, the methods from the base-class interface come right along into the derived class. That means objects of the derived class have not only the same type, they also have the same behavior, which isn&#146;t particularly interesting. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_146" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>You have two ways to differentiate your new derived class from the original base class. The first is quite straightforward: You simply add brand new methods to the derived class. These new methods are not part of the base class interface. This means that the base class simply didn&#146;t do as much as you wanted it to, so you added more methods. This simple and primitive use for inheritance is, at times, the perfect solution to your problem. However, you should look closely for the possibility that your base class might also need these additional methods. This process of discovery and iteration of your design happens regularly in object-oriented programming. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_147" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><a name="Index87"></a><a name="Index88"></a><img src="TIJ308.png" 	alt="TIJ308.png" border="0" ><br></p>
<p>Although inheritance may sometimes imply (especially in Java, where the keyword for inheritance is <b>extends</b>)<b> </b>that you are going to add new methods to the interface, that&#146;s not necessarily true. The second and more important way to differentiate your new class is to <i>change</i> the behavior of an existing base-class method. This is referred to as <a name="Index89"></a><a name="Index90"></a><i>overriding</i> that method. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_148" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><img src="TIJ309.png" 	alt="TIJ309.png" border="0" ><br></p>
<p>To override a method, you simply create a new definition for the method in the derived class. You&#146;re saying, &#147;I&#146;m using the same interface method here, but I want it to do something different for my new type.&#148; <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_149" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545194"></a><a name="_Toc408018391"></a><a name="_Toc472654687"></a><a name="_Toc24775519"></a><a name="Heading1066"></a>Is-a
vs. is-like-a relationships<br></h3>
<p><a name="Index91"></a>There&#146;s a certain debate that can occur about inheritance: Should inheritance override <i>only</i> base-class methods (and not add new methods that aren&#146;t in the base class)? This would mean that the derived type is <i>exactly</i> the same type as the base class since it has exactly the same interface. As a result, you can exactly substitute an object of the derived class for an object of the base class. This can be thought of as <i>pure substitution</i><a name="Index92"></a>, and it&#146;s often referred to as the <a name="Index93"></a><i>substitution principle</i>. In a sense, this is the ideal way to treat inheritance. We often refer to the relationship between the base class and derived classes in this case as an <i>is-a</i> relationship, because you can say &#147;a circle <i>is a</i> shape.&#148; A test for inheritance is to determine whether you can state the is-a relationship about the classes and have it make sense. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_150" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>There are times when you must add new interface elements to a derived type, thus extending the interface and creating a new type. The new type can still be substituted for the base type, but the substitution isn&#146;t perfect because your new methods are not accessible from the base type. This can be described as an <i>is-like-a</i> relationship (my term). The new type has the interface of the old type but it also contains other methods, so you can&#146;t really say it&#146;s exactly the same. For example, consider an air conditioner. Suppose your house is wired with all the controls for cooling; that is, it has an interface that allows you to control cooling. Imagine that the air conditioner breaks down and you replace it with a heat pump, which can both heat and cool. The heat pump <i>is-like-an</i> air conditioner, but it can do more. Because the control system of your house is designed only to control cooling, it is restricted to communication with the cooling part of the new object. The interface of the new object has been extended, and the existing system doesn&#146;t know about anything except the original interface. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_151" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><img src="TIJ310.png" 	alt="TIJ310.png" border="0" ><br></p>
<p>Of course, once you see this design it becomes clear that the base class &#147;cooling system&#148; is not general enough, and should be renamed to &#147;temperature control system&#148; so that it can also include heating&#151;at which point the substitution principle will work. However, this diagram is an example of what can happen with design in the real world. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_152" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>When you see the substitution principle it&#146;s easy to feel like this approach (pure substitution) is the only way to do things, and in fact it <i>is</i> nice if your design works out that way. But you&#146;ll find that there are times when it&#146;s equally clear that you must add new methods to the interface of a derived class. With inspection both cases should be reasonably obvious. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_153" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545195"></a><a name="_Toc408018392"></a><a name="_Toc472654688"></a><a name="_Toc24775520"></a><a name="Heading1072"></a>Interchangeable
objects <br>with polymorphism<br></h2>
<p><a name="Index94"></a>When dealing with type hierarchies, you often want to treat an object not as the specific type that it is, but instead as its base type. This allows you to write code that doesn&#146;t depend on specific types. In the shape example, methods manipulate generic shapes without respect to whether they&#146;re circles, squares, triangles, or some shape that hasn&#146;t even been defined yet. All shapes can be drawn, erased, and moved, so these methods simply send a message to a shape object; they don&#146;t worry about how the object copes with the message. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_154" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Such code is unaffected by the addition of new types, and adding new types is the most common way to extend an object-oriented program to handle new situations. For example, you can derive a new subtype of shape called pentagon<i> </i>without modifying the methods that deal only with generic shapes. This ability to easily extend a design by deriving new subtypes is one of the essential ways to encapsulate change. This greatly improves designs while reducing the cost of software maintenance. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_155" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>There&#146;s a problem, however, with attempting to treat derived-type objects as their generic base types (circles as shapes, bicycles as vehicles, cormorants as birds, etc.). If a method is going to tell a generic shape to draw itself, or a generic vehicle to steer, or a generic bird to move, the compiler cannot know at compile time precisely what piece of code will be executed. That&#146;s the whole point&#151;when the message is sent, the programmer doesn&#146;t <i>want</i> to know what piece of code will be executed; the draw method can be applied equally to a circle, a square, or a triangle, and the object will execute the proper code depending on its specific type. If you don&#146;t have to know what piece of code will be executed, then when you add a new subtype, the code it executes can be different without requiring changes to the method call. Therefore, the compiler cannot know precisely what piece of code is executed, so what does it do? For example, in the following diagram the <b>BirdController</b> object just works with generic <b>Bird</b> objects and does not know what exact type they are. This is convenient from <b>BirdController</b>&#146;s perspective because it doesn&#146;t have to write special code to determine the exact type of <b>Bird</b> it&#146;s working with or that <b>Bird</b>&#146;s behavior. So how does it happen that, when <b>move(&#160;)</b> is called while ignoring the specific type of <b>Bird</b>, the right behavior will occur (a <b>Goose </b>runs, flies, or swims, and a <b>Penguin</b> runs or swims)? <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_156" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><img src="TIJ311.png" 	alt="TIJ311.png" border="0" ><br></p>
<p>The answer is the primary twist in object-oriented programming: the compiler cannot make a function call in the traditional sense. The function call generated by a non-OOP compiler causes what is called <a name="Index95"></a><a name="Index96"></a><i>early binding</i>, a term you may not have heard before because you&#146;ve never thought about it any other way. It means the compiler generates a call to a specific function name and the linker resolves this call to the absolute address of the code to be executed. In OOP, the program cannot determine the address of the code until run time, so some other scheme is necessary when a message is sent to a generic object. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_157" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>To solve the problem, object-oriented languages use the concept of <a name="Index97"></a><a name="Index98"></a><i>late binding</i>. When you send a message to an object, the code being called isn&#146;t determined until run time. The compiler does ensure that the method exists and performs type checking on the arguments and return value (a language in which this isn&#146;t true is called <a name="Index99"></a><a name="Index100"></a><i>weakly typed</i>), but it doesn&#146;t know the exact code to execute. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_158" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>To perform late binding, Java uses a special bit of code in lieu of the absolute call. This code calculates the address of the method body, using information stored in the object (this process is covered in great detail in Chapter 7). Thus, each object can behave differently according to the contents of that special bit of code. When you send a message to an object, the object actually does figure out what to do with that message. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_159" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>In some languages you must explicitly state that you want a method to have the flexibility of late-binding properties (C++ uses the <b>virtual</b> keyword to do this). In these languages, by default, methods are <i>not</i> dynamically bound. In Java, dynamic binding is the default behavior and you don&#146;t need to remember to add any extra keywords in order to get polymorphism. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_160" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Consider the shape example. The family of classes (all based on the same uniform interface) was diagrammed earlier in this chapter. To demonstrate polymorphism, we want to write a single piece of code that ignores the specific details of type and talks only to the base class. That code is <a name="Index101"></a><i>decoupled</i> from type-specific information and thus is simpler to write and easier to understand. And, if a new type&#151;a <b>Hexagon</b>, for example&#151;is added through inheritance, the code you write will work just as well for the new type of <b>Shape</b> as it did on the existing types. Thus, the program is <i>extensible</i>. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_161" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>If you write a method in Java (as you will soon learn how to do): <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_162" title="Send BackTalk Comment">Feedback</a></font><br></p>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> doStuff(Shape s) {
  s.erase();
  <font color=#009900>// ...</font>
  s.draw();
}</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>This method speaks to any <b>Shape</b>, so it is independent of the specific type of object that it&#146;s drawing and erasing. If some other part of the program uses the <b>doStuff(&#160;)</b> method: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_163" title="Send BackTalk Comment">Feedback</a></font><br></p>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Circle c = <font color=#0000ff>new</font> Circle();
Triangle t = <font color=#0000ff>new</font> Triangle();
Line l = <font color=#0000ff>new</font> Line();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -