Vous êtes sur la page 1sur 182
A Little Java, A Few Patterns. Contents Foreword ix Preface xi Experimenting with Java xii 1. Modern Toys 2. Methods to Our Madness 13. 3. What's New? 43) 4. Come to Our Carousel 57 5. Obpets Are People, Too 68 6. Boring Protocols 86 7.Oh My! 99 1. Like Father, Like Son 117 9. Be a Good Visor 159 10, The State of Things to Came 161 Com nt AIT Index 178 Copyrighted material FOREWORD Learning to program is more than learning the syntactic and semantic rules of a programming language. It also roquires learning how to design programs. Any good book on programming ‘must therefore teach program design Like any other form of design, program design has competing schools. These sliools are often associated with a particular set of languages. Since Java is an object-oriented programming language. people teaching Java should emphasize object-oriented! design Felleisen and Friedman show that the functional (iyput-ontput driven) method of progeans design naturally leads to the use of wellknown object-oriented design patterns. In fat. they integrate the two styles seamlessly and show bow well they work together, Their book proves that the functional design method does not clash with, but supports object-oriented programming, ‘Their succoss doesn’t surprise me, becanse I've seen it in Smalltalk for many years, though unfortunately, it seems to have remained one of the secrets of object-oriented design. Tn happy to sce that Fellenen and Friedman have finally exposed it. This hook will be especially useful if you are a C++ programmer learning Java, since you probably: haven't seen fanetionsl program design before. If you know funetional design, the book will gently introduce you 10 pattern-based programming in Java. If you don't know it, Fellesen and Friedman will teach you a powerful new way of thinking that you should add to your design toolbos. Enjoy the pizzas! Ralph B. Johnson ‘Champaign, Mlinois Preface ‘An object-oriented programming language enables a programmer to construct reusable program ‘components. With such components, other programmers can quickly build large new programs tnd program fragments. In the ideal case, the programmers do not modify any existing code but simply glue together components and add a few new ones. This reusability of components, however. does not come for free. It requires a well-designed object-oriented language and a strict, discipline of programming Java is a such & language, and this book introduces its object-oriented elements: (abstract) classes, fields, methods, inheritance, and interfaces. This small core language has a simple semantic model, which greatly helps programmers to express themselves. In addition, Java implementations automatically manage the memory a prograin uses, which fres programmers from thinking about machine details and encourages them to focus on design. ‘The book's second goal is to Introduce the reader to design patterns, the key elements of a programming discipline that enhances code reuse. Design patterns help progeammers organize their object-oriented components so that they properly implement the desired computational process. More importantly stil, design patterns help communicate important. properties about 1 program component. If » component is an instance of an explicitly formulated pattern and ‘documented as such, other programmers can easily understand its structure and reuse it in their ‘own programs, even without access to the component's source. "THe INTENDED AUDIENCE The book is primarily intended for people—practicing programmers, instructors and students alike—who wish to study the essential elements of object-oriented programming and the idea ‘of design patterns. Readers must have some basic programming experience. They will benefit ‘most from the book if they understand the principles of functional design, that i, the design ‘of program fragments based on their input-output behavior, An introductory computer science ‘course that uses Scheme (or ML) is the best way to get familiar with this style of design, but it is not required. Wuar This Book 1s Nor Anovr Java provides many useful features and libraries beyond its objectoriented core. While these ‘additional Java elements are important for professional programming, theie coverage would distract from the book's important goals: object-oriented programming and the use of design patterns. For that reason, this book is not complete introduction to Java. Still, readers ‘who master its contents can quickly become skilled Java programmers with the supplementary sources listed in the Commencement. The literature on design patterns evolves quickly. Thus, there is quite a bit more to patterns than an introductory book could intllgibly cover. Yet, the simplicity of the patterns we use and the power that they provide should encourage readers to study the auditional references about patterns mentioned at the end of the book, AckNowLeDcMents We are indebted to many people for their contributions and assistance throughout the devel- ‘opment of this book, Several extensive diseussions with Shriram Krishnamurthi, Jon Rossie, ‘and Mitch Wand kept us on track; their detailed comments deeply influenced ou thinking at critical junctures. Michael Ashley, Sundar Balasubramaniam, Cynthia Brown, Peter Drake, Bob Filman, Robby Findler, Steve Ganz, Paul Graunke, Jobin Greiner, Erik Hilsdale, Matthew Kudein, Julia Lawall, Shinn-Der Lee, Michael Levin, Gary McGraw, Benjamin Pierce, Amr Sabry; Jonathan Sobel, and George Springer read the book st various stages of development and ‘eit comments helped produce the final result. We also wish to thank Robert Prior at MIT. Press who loyally supported us for many years and fostered the ie ofa “Little Java." The book greatly benefited from Doral Sitaram's incredibly clever Scheme typesetting program SIETEX. Finally, we would like to thank the National Science Foundation for its continued support ‘and especially for the Educational Innovation Grant that provided us with the opportunity to collaborate for the past year REapNe GUIDELINES Do not rush through this book, Allow seven sittings, atleast, Read carefully. Mark up the book ‘or take notes: valuable hints are scattered throughout the text. Work through the examples, don't scan them. Keep in mind the motto “Think fist, experiment later ‘The book is a dialogue about interesting Java programs. After you have understood the ‘examples, experiment with them, that is, modify the programs and examples and see how they Thehave. Since most Java implementations are unfortunately batch interpreters or compilers, this requires work of a repetitive nature on your side. Some hints on how to experiment with Java fre provided on the following pages. ‘We do not give any formal definitions in this book. We believe that you can form your own definitions and thus remember and understand them better then if we had written them out for yout. But be sure you know and understand the bits of advice that appear in most chapters We use a few notational conventions throughout the text to help you understand the programs on several levels. The primary conventions concera typeface for different kinds of words, Field and method names are in italic. Basic data, including, numbers, booleans, and constructors introduced via datatypes are set in sans serif’ Keywords, eg, class, abstract, return and interface are in boldface. When you experiment, you miay ignore the typefaces Iput uot the related framenotes. To highlight this role of typefaces, the programs in framenotes ave set in & typewriter face. Food appears in many’ of our examples for two reasons. First food is easier to visualize than abstract ideas. (This is not @ good book to read while dieting.) We hope the choice of food will help you understand the examples and concepts we use. Second. we Want to provide ‘you with a little distraction, We know how frustrating the subject matter can be, aul «litte slistraction will help you keep your sanity You are now ready to start. Goad luck! We hope you will enjoy the experiences waiting for ‘you on the following pages. Bon appétit! ‘Matthias Felleisen Daniel P. Friedman EXPERIMENTING WITH JAVA re are some hints on how to experiment with Java:! 1. Create a file that contains a complete hierarchy of cass, 2. To each class whose name does not end with a superscript D, V,T, or M, add a toString ‘method according to these rules: 4) ifthe class does not contain any fields, use public String tostring() { return "new " + getClase().getNane() + "0"; ) by) if the class has one fild, say x, use public String toString() { return "new" + getClass().getName() + "(" +x #""; > <) i the class has two fields, say x and y, use public String toString() { return "new" + getClase().getNane() + 8. Ada the following class at the bottom of the file: class Main ( public static void eain(String arget }) DataType.or Interface y= nev : se Systen.out printlaC . With DavaType.or-Interface y = new - - - - ., create the object y with which you wish to experiment, Then replace ...... with the example expression that you would like to experiment with. For example, if you wish to experiment with the distanceTeO method of NashattanPt 1s defined in chapter 2, add the following definition to the end of your file class Main { public static void main(String arget J) { PointD y = new ManhavtanPt (2,8); Systen. out printin( y.distanceToO() ); } } Sex Arnold and Gosling i] for deals on how they work, These hints make itl sense ot of coment, for I you wish co experiment with a sequence of expressions that modify y. asin chapter 10. ¢.9 Pee ere aeeeeen eee replace -. +++ with, Yooeee eters yolllilenats a For example, if you wish to experiment with the methods of Piesant as defined in chapter 10 rad the following definition to the end of your fe: class Main ( public static void aain(String argal 1) < Piomanl y = now Piemant(; Systes.out .printin( Yy-addTop(aew Anchovy()) + "\n" + yoaddTop(aey Anchovy) + “\nt + y-substTop(new Tuna(),ne¥ Anchovy()) i } > 4. Finally, compile the fle and interpret the class Maia, He Teledleiria Tews 1 5 an integer? Is this « number: ~23? Is this Imveger: 5.327 ‘What type of mmber is 5? Quick, think of another integer! What type of value is true? What type of value is false? ‘Can you think of another boolean? ‘What is int? ‘What is boolean? What is a type? What isa type? (Can we make new types? Modern Toys Yes, it is. Yes, but we don't use negative integers * No, and we don't use this type of number. “int. * How about 197 * boolean, boolean, No, thats all there is to boolean. * Atpe, "Another type. in of values A type is a name fora cole * Sometimes we use it as it were the collection We don't know how vet Draw the picture that characterizes the ‘essential relationships among the following clases [ abstract class Seasoning” {) class Sat extends Seasoning? {) class Pepper extends Seasoning” {} lags Yes. We say Seasoning? is a datatype, and Salt andl Pepper are its variants Yes, in a way. Now. is new Salt) 1 Seasoning”? And new Pepper()? are abstract, class, and extends? Is there any other Seasoning? "Is this ie? ‘Salt Pepper Okay, But aren't all three clases introducing new types? ™ Yes, it is, because new Sal() creates an instance of Salt, and every instance of Salt is also Seasoning?. "Te also & Seasoning, because new Pepper) creates an instance of Pepper, and every instance of Pepper is also a Seasoning”. * Basy: ‘abstract class introduces a datatype, class introduces a variant, and ‘extends connects # variant to a datatype. No, because only Salt and Pepper extend Seasoning?" Chapter 1 Correct, Salt and Pepper are the only. variants ofthe datatype Seasoning”. Have swe seen a datatype like Seasoning” before? Let's define more Seasonings “ [class Thyme extends Seasoning? (} | ‘And then there were four. a What is a Cartesian point? a ‘What is point in Manhattan? How do CartesianPt and ManhattanPt differ from Salt and Pepper? abstract class Point? {} ‘lass CartesianPt extends Point” { int = int y GartesianPa(int 2.int y) { [class ManhattanPt extends Point { J ine { ine y ManhattanPx(int int.) ( No, but boolean isa type that also has just toro values We can have lots of Seasonings —_ Yes. It is basically & pair of numbers. ‘An intersection where two city streets meet Each of them contains three things between {and }. The x and the y are obviously the ‘coordinates of the points. But what is the remaining thing above the bold bar?! The wateelined occurences of CartesianPt “How do we use these constructors? ‘uy MaghattanP inteoduce: the constmictors of the respective variants. A constructor is sel with new to create" Obvions! new instances of « elas. When we create CartesianPt like this: So now we have eveated a CartesianPt whee anew CartesianPt(23), 2 fied is 2 and whose y field is 3. An because CartesianPt extends Point? itis also a Point? we use the constructor i the definition of CartesianPt Correct, Is tis a ManhattanPt ‘Vesa its il is 2 ality fe is 3 ‘ew ManhattanPt2.3)? Inat allthis obvious? ™ Msty, but that means we have used constructors before without defining ther. How does that work? When a class dows not contain any fckls. as" Ane! that's the coustmctor ww sl ofore, it Salt wil Pepper. cotstructor is ichided right? Ie ofl Yes. that’s correct. Defanlt constructors reser cone values, std, when used with now, sivas ereate objects without fields Good, But what is mew Point™()? An abstract clas is by definition ‘That makes sense. Let's move on, incomplete, x0 new cannot create an instance For it 6 Chapter 1 Do the following clases define another datatype with variants? abstract class Num” {) * Yes, they define a datatype and two variants / Num? ‘lass Zero extends Num” {} ‘lass OneMoreThan extends Num? { Num? predecessor, OneMoreThan(Num® .p) { predecessor =p: } iD Draw the picture, too. Is this « Num?: new Zero()? Is this a Num?: new OneMoreThan rnew Zero())? How does OneMoreThan do that? ‘And shat does it mean to construct this new Does predecessor always stand for an instance of Zero? Modern Toys 2 Zero [OneMoreThan| ‘Obviously just ike mew Sale) i a Seasoning” * Yes, hecanse OneMoreThan constructs & Num? from a Num®. and every instance of OneMoreThan is also a Num? We give it new Zero(), which is @ Num. and it constructs a new Num?. This new instance of OneMoreThan is a value with a singe fed, which is called predecessor. In our example, the fel is ‘new Zera() No, its type says that it stands for & Num? which, at the moment, may be either a Zero ‘or 8 OneMoreThan. What is new OneMoreThan( ‘new OneMoreThan( new Zerol)))? Wat is new OneMoreThan( oy Is new Zerol) the same as 0? & ‘new OneMoreThan( ‘new Zero\)) like ra And sehat is ‘new OneMoreThan ‘new OneMoreThan( ‘new OneMoreThan( ‘new OneMoreThan( ‘new Zero()}))) Ave there nore Num?s than booleans? Are there more Num®s than ints? "A Num®. becasse OneMoreThan constructs from a Num® andl we aged ‘new OneMoreThan{ new Zero()) Ja Num? ‘That is nonsense," because 0 is not a Num? ar to, but not the same as Lis similar to, but not the sare new OneMareThan( ‘new Zero) 4 Lots Not Chapter 1 ‘What is the dlference between new Zero() and 0? Correct. In general, if two things are instances of two different base types, they cannot be the same, ‘The primitive types (Int and boolean) are distinct: others may overlap. Class definitions do not introduce primitive vpes. For example, a value like new Zero() is not only an instance of Zero, buts also Num®. which is extended by Zero. Indeed, it is of any type that Num? extends, to. Every class that does not explicitly extend another class implicitly extends the class Object. Almost, We will soon sce what that means Easy: new Zero) is an instance of Zero and, bby implication, is a Num®, whereas 0 is an int. This makes it dificult to compare them, Dat we can compare thei in our minds. So are types just names for different collections with no common instances? What are non-basie types? And what is that? "This must mean that everything is an Object. * Okay: ‘The First Bit of Advice When specifying a eoection of data, use abstract classes for datatypes and tertended classes for variants, Modera Toss What do the following define? abstract class Layer” class Base extends Layer? ( Object 0: Bae Oveet 0 | } class Slice extends Layer? { Layer StcelLaye” 1) { t=} What is new Basel ‘new Zero)! Aud what is ‘new Base( new alti)? They are, because everything created sith new is an Object. the class of all objects 0 “They define a new datatype and its 190 vats. The fist caviant contains fel of type Object Tr looks like an instane of Base, which reais it is abo a Layer? and an Object. 1 also looks like an instance of Base Dit how come bath ‘new Base, ‘new Zerat)) ane new Base! ‘new Salt) now Zero and ‘new Salt) for the eonstnction of « Base, which requires an Object Chapter 1 Is anything else an Object? Correct. Is this a Layer Is this a Layer: new Base false? Correct agnin! How about this Layer? new Base( new Integer(5))? Guess how we ereate a Layer? from false? Is it confusing that we need to connect int ‘with Integer and boolean with Boolean? Ready for more? Modern Toys ‘We said that only things created with new are Objects? 5 is not created with mew, so this must be false is not created with new, so this must be nonsense, to. ‘This must meas that Integer creates an ‘object from an int, Basy now: new Base( new Boolean(false)) ‘Too much coffee does that Can't wait. sem re * = 2@) ip ~ - Remember points? abstract class Point? ( rae — Cid int 2; int; CaresianPt(int int _y) { v=) ‘lass CartesianPt extends Point? { | | = Ceneiae po ‘lass ManhattanPt extencls Point? { int 5 in | ManhattanPt(int 2.int y) { | vs) = | ‘We will find out soon. Did you notie the big white space on the right? How far is new ManhattanPt(3.4) from the Empire State Building? ‘And how far is new CartesianPt(3.4) from the origin? Methods to Our Madness "Sure, we just talked about them, But what are these labeled ovals about * Te must be for drawing the picture of the classes. the Empite State Building is the origin, we have to walk seven blocks: 3 over, 4 up. * 5, which is VIEW, 13 Write the methods distanceT@O using (.).(.” Of course, you can't write these methods, return. int. + [Vand 2, which set, Oka. you deserve something sweet for leteriine how fara point is front the origin, enduring this last question What do che methods produce” Its, whicl represent the distances to the origi. Hore they ar They correspond to the unexplained! labels in the definition of the datatype aod its abstract int disaner 700): writs int distance THO { return CartesianPe ine ister To) ( return 4: } MauhattanPe Tis what do Point, CartesionPt, and MonhattiaiPt in the boxes refer? ‘he babes reruns that we need to insert" ‘That's sinuple emg Hwee mits nto Point®, CartsianPt, and Manhattan Hoe many tines have we defined the metho” ‘Thee tines, but the Bist one difers eon the distance ToO? other to. Tt labeled abstraet, while the bthers ate not preceded by a special woe Chapter 2 Do abstract methods belong to the "Yes, they always do abstract class? ‘An abstract method in an abstract class” Okay: introduces an obligation, which says that all concrete classes that extend this abstract class! must contain a matching method. efinition What is the value of eo ‘new ManhattanPt(3.4) distanceToO()? How do we arrive at that value? We determine the value of zy, with replaced by 3 and y replay 4 What i the valu of 5; because tha is the value of new CartesanPt(2A) 7 distanceToO()? vee with 2 replaced by 3 and y replaced by 4 What does [] compute? ‘The largest int that does not exceed the square root of 2 ‘Time for a short break? An apple a day keeps the dentist away. A ‘cup of eaffee does not Methods to Our Madness Here is another datatype with its variants What is different nbout theta? abstract class Shish® { Shih ieee class Skewer extends Shish® { (Shower } | class Onion extends Shish? ( Shih? Onion Ssh?) { =) class Lamb extends Shish? { Shish? LambiShish? 3) { een) class Tomato extends Shish? ( Shish? Tomato|Shish® 5) { sy Did yon notice the big space on the right? 6 1s ke Num? but thas more variants, "Yes, isn't it for drawing the picture of the clases? Chapter 2 Construct a Shish®, Yes, every Skewer is also a Shish®. How about another one? ‘And a third? ‘Are there only Onions on this Shish®: new Skewer()? ‘Are there only Onions on this Shish?: new Onion( new Skever())? How about new Skewer()? Here's one ‘new Onion( new Skever(). * Here's one more: rnew Onion( new Lamb( new Onion( new Skewer())) true, because there is neither Lamb nor Tomato on new Skewes () tre And how about: new Lamb new Skewer())? Te it trve that new Onion( ‘new Onion( new Onion( new Skewer()))) contains only Onions? ‘And finally: ‘new Onion( new Lamb( ‘new Onion( ‘new Skewer())))? Methods to Our Madness fale, false. wv Write the methosls onfyOnuons! sig (Jo (. 7 OF conse, you can’t write these methods ).- itt, fase, return, and boolean, yet. Okay, you deserve a lllipop for ‘evalua, Chis Kt of question gai Aut whut do they preduce? boolean Here aoe tue mths Yes. Wo snd abu that the labeled ovals i the center of the Dla Hines i the above ‘lags fits tells where to put the boxes with the corresponding label abstract boolean vnlyOnions() Shit boolean vnlyOnions) { return true} Skewer boolean onlyOnions() ( return sonlynions): } Onion boolean onlyOnions() | return false. } Lamb boolean onlyOnions() { ‘return fe: | Tomato Dial yon notice the Inbets in the boxes? Good, Howe many mettids have we defined? "Five, but the fist one fs abstract: he ‘others ate cunerete Chapter 2 Do abstract methods belong to the abstract class? Does each variant of Shish® contain a method called onlyOntons? Is this always the case? What do these concrete methods consume? What do these concrete thods produce? What is the value of ‘new Onion( ‘new Onion( ‘new Skewer())) conlyOnionst)? ‘And how do we determine the value of ‘new Onion( ‘new Onion( ‘new Skever())) onlyOnions()? Which definition of onlyOnions must we use to determine the vale of new Onion ‘new Onion( new Skewr()) onlyOnions)? Methods to Our Madness Yes, we sid to. ‘Yes, because Shih contains an abstract method called onlyOnions that obligates ach variant to define a matching, concrete sethod. Always Nothing. just as the abstract method savs. Dooleans, just as the abstract method says te, We will need to pay attention to the method definitions, * This object is an instance of Onion, so we need to use the definition of anlyOnions that belongs to the Onion variant. Wit follows the word return in the ‘anlyOnions wethod in Onion? Wits the fel sof the object 1ew Onion( ‘new Onion( thew Skewer()))? Does also stad fort Onion? Then what is womlyOniona)? Wily da we el to kaw the menning of new Onion( ‘new Skewer()) sonlyOnions)? How do we determine the answer for ‘new Onion( new Skewer|) sonlyOnions)? sonlyOnionsi) his new Onion( new Skewer)) No, it has type Shish®, and it can stand for ‘ay variant of Shih: Skewer, Onion, Lamb, ‘or Tomato, It should be rnew Onion( new Skewer)) donlyOnions) right? Becanse the answer for new Onion( ‘new Skewer()) donlyOnions) is abo the answer for new Onion( ‘new Onion( ‘new Skewer())) onlyOnions). Let's see Chapter 2 Which definition of onlyOnions must we use to determine the value of new Onion( new Skewer() conlyOnions)? ‘What follows the word return in the donlyOnions method in Onion? What is the field 6 of the object new Onion( new Skever())? ‘Then what is s.onlyOnions()? Why do we need to know the meaning of new Skewer() conlyOnionst)? How do we determine the answer for new Skever() ‘onlyOnions)? Methods to Our Madness ‘This object is an instance of Onion, so we need to use the definition of onlyOnions that belongs to the Onion variant. ‘.0nlyOnions() new Skewer() tis new Skewer() ‘onlyOnions). Just as we would have expected. cause the answer for ‘new Skewer() ‘nlyOnions() Js also the answer for new Onion( ‘new Skewer()) } Pizza” forSiusaye(Piaza? p) { return new Sausage| p.sih.AbC()): } ' Chapter 4 we Fay “ Pe Have we seen this kind of definition before?! ' What? More pizza! [abateact class Pie? ( | j= Z a class Bot extends Pie? pana ‘lass Top extends Pie” { ] ‘Object: Pie” Top(Object -t,Pie® -r) { | | | | —-C=— | bo this one is diferent. *” Yes, it includes only one variant for adding toppings to pizza, and toppings are Objects ‘Yes, still more pizza, ‘What kind of toppings can we put on these * Any kind, because Object isthe class ofall kinds of pizaa? objects. Here are some fish toppings. abstract class Fish? {) ‘lass Anchovy extends Fish? {) ‘lass Salmon extends Fish® {) ‘ease Tuna extends Fish? () Objects Are People, Too oo Nice datatype, bs new Topinew Anchovy sw Topinew Tuna). jew Topinew Anchovy) ‘new Bott) ss pirea pie? What is the vale of new Topinew Salmon) new Topinew Anchovy), new Topinew Tuna nnew Topinew Anchovy) ‘new Bot)))) rym? Is ie aro that the vale of new Topinew Saimon|| new Topinew Tuna) ‘new Bot) mai new Topinew Salmont) ‘now Topinew Tonal) ‘new Botl)))? Does ronal beg to Pie? Deine the protocol for RemAY. Wie provide the abstract ptt RemAY muy = new Rema") abstract Pie® rin() Pie 1 is pez pi, ats new Topinew Tuna) ww Top(new Integer 42) wew Topinew Anchovy) ow Topinew lnteger'5) new Bott) 1k eh fia pizza pe rew Toplniew Salmon) new Top(new Tuna) sw Bot). Yes. The pizza that cones ont isthe sn theme that goes in, eeatbe there ate suelo a that pian Yes, and it prone pin pies This is sy by ne Pie wma) { return ruPforBot(): ) Bot Pie? roma) { return saFa forTop( tanh) Ty Chapter 5 Great. Isn't that easy? ‘What part of this exercise differs from datatype to datatype? Anything else? Why (109)? Let's define the visitor RemAY [eta ema Pie? forBort) { return Pie? for Top(Object (Pie? 1) { it (now Anchovy) .equalst)) return | abe || return} | p Great guesses! What does it(expr) return expr else return expr And what does new Anchovy().epuals(t) Not yet. It depends on what equals means Objects Are People, Too ° Basy and boring ” Determining how many fields a variant ‘contains. In our case, we had zero and two. * No from that we know that Fn forBor is followed by () and maFnforTop by (t.), ” Because these ae the feds of Top, Here are some guesses. class nl Pie? [eaten { return new Bot): } | Pie? forTop( Object 1.Pie? ¥) { it (how Anchovy). equals(t) return rrema() lse bo return new Top(torrema()):) We guess “This produces the value of either expr or exprs, depending on whether of not expr is determined to he true or fase respectively * We could guess: “This expression determines whether s sequal to new Anchovy) What? Whats the value of The “Not yet” implies that the vale is false, new Anchowy().rquala(new Anchovy())? Yes! Anal what is the wale of fale new Anchovy). cquals(new Tuna)? Tasca nacho fst The class Object contains a method called — "Af we kuow tat equals answer is als ‘equals. This method eompates one Object to false, why botber to use it? another, nd it always returns falge.! We seine it anew? forall classes whose "Okay. How? instances we sesh to compare For Fish? and its variants it works hike this," Assuming that [o instanceof Tuna) is true whew isa instance of Tuna. these abstract class Fish? {} tuethid definitions sre obvi class Anchovy extends Fish? { public! boolean equals(Object 0) { return (o instanceof Anchovy): } } lass Salmon extends Fish? ( publie boolean equas(Object 0) ( return (0 instanceof Salmon): } } class Tuna extends Fish? { public boolean rquals(Object o) return (0 instanceof Tuna): ) a Chapter 5 Aren't they? Is every value constructed with” new an instance of Object? If class A extends B. is every value created by mew A(...) am instance of class B? Now, what is the value of new Anchovy()-equals(new Aachovy())? Yet the value of new Anchovy()-cquals(new Tuna()) is til fale Could we have written RemAY ssithout using” equals? Easy, because we want to generalize RemAY” 0 that it works for any’ kine of fish topping What are good names for the mote general ‘methods and visitor? Objects Are People, Too Yes. Every such wale is an Object, boca every class extends Object direct of indirectly ‘Yes, aud of the class that B extends aul so OF course, ecnnse nn anchowy is over 8 Absolutely, instanceof is enon [class Rema ( Pie? forBot() { return now Bot) } Pi forTup(Object tie? 7) { if (instanceot Anchow) return nin) | else return new Top(tiremat):} ) ‘Why haven't we defined it this way? * We can do that, but when we use the methods ofthe more general visitor. we need to say whieh kind of fish we want to remove. * How about remFish and RemFishY? How do we use sem Fish? [Add the protocol for RemFish®. We designed the abstract portion RemFish’” rfFn = new RemFish®() abstract Pie remFish(Fish? J) Where do (f) and (2.7) come from? Let's define RemFish”” and its two methods I we adel another kind of fish to our datatype, what would happen to the definition of RemFish”? "We give it Fish”. © The rest is eotine, Pie? remFish(Fish® f) { return rf x forBot(f): } Bot Pie? remFish(Fish® J) { return rfFr forTop(tor fs} Top The f stan forthe Fish® wee want 10 ve ity uth eases, The fad the 7 are the fields of Top: Bot doesn't hase any "Instead of comparing the top layer 1 of the pizza to Anchovy, we nog determine whether 1 equals the Fish? f. which is the aditional value consid bythe nth class Reman” { Pie? forBo(Fish? f) | return new Bett): Pie? forToplObject Pie” vFsh” f) { it ena) return rn Fisd(f) ‘else return new Top. iFis): } ) Nothing, we just ave to renwenbor to dl ‘equals to the new variant Chapter 5 Let's try it out with a short example: new Top(new Anchovy), new Bet()) semFish(new Anchovy()) Yes. What values does forTop consume? And now? Sor What is the value of new Bet() remFish(new Anchovy())? ‘What does forBot in RemFishY produce? All lest? Objects Are People, Too ‘The abject is topping, s0 we use forTop from RemFish”. Tt consumes thee values: new Anchovy(), ‘which ist, the top-mast layer of the pizza new Bot(), whieh is r, the rest of the pizza: tnd new Anchowy(). which is f. the Fish? to be removed, Now we need to determine the value of If (Lequas(t)) return rremFish(f) else return new Top(t.rremFish(f)): where ¢, rand f stand forthe values just mentioned, Given what f and ¢ stand for, fequals(t) is true. Hence, we must determine the value of rremBish(f). Tis the same as JorBot(f), where fis mew Anchovy), It produces mew Bot(), no matter what fis. Ready to move on, after snack time, % "Vox. has ike what we just vubte new Integer 3} new Top(new Integer(2). new Bot! )}!) re vernew Integer 3}) lok fiir? Wht does senda ds 1 removes Integers fin pizen pies just vmPish tonne ish fra piece pi Who tis pals for Integer? The Machine devils new Integer 0). yunls|mew Integeri0)) te ae trie ae test ys vt Dain the visitor Remint® Wonrerfull We do the interesting thing firs ‘This visitor is alum! identval to RemFish We Just wed to clange the type of what the tao ets const class Remint” { Pie? forBot(integer i) | return new Bot(l: | Pie® forTap( Object (Pie! rInteg if (equals) return /.1rrfut(e) else rretura new Topl tir lit\i)s ) Does it matte tat tis detinitions ses Fatal No, Fb just a etter tne Oia f. ne other wot f ress As lng swe do sich sibttations steumaticaly, we ate jist Fie Wheve isthe protorol” Desa simple, lets save it Gr Later ww Chapter 5 Can we remove Integers from Pie ‘Can we remove Fish from Pie®s? Let's combine the two definitions Why? Just doit! Should we do the protocel for all these ‘You never know when it might be useful even if it does not contain any interesting. information, Why not RemFish” and RemAY and Remlnt”? Objects Are People, Too Yew. ‘Yes, and we use nearly identical definitions. IF we use Object instead ofthe underlined Integer above, everything works out Because everything constructed with new is fan Object. es done, Pie® forBot(Objet 0) return new Bot) } Pi? forTep(Object Pie? Object 0) {| FF (sequal) return remo): | else return new Top(¢-rn(o) } be Bo [ee Rem { | Now? Let's just consider Rem” ‘They are unnecessary once we have Rem™ Jove is the abstract portion of Pie Al ere are the pieces for Bot sad Top. abstract class Pie | lass Bot extends Pie” { Rem? iymifn — new Rem) Pie? rein(Object o) | abstract Pie™ min(Objet 0) return sen forBot(o): } ' } class Top extends Pie? { Object: Pie? r: Top(Odject Pie? -r) { raun) Pie? rrin(Object 0) | return rem Bn forTup( trols} ' Let's ren some ings from pean piss“ Works lke a lsu ith the sae rest as snow Topinew Integer(2) befor. new Topinew Integer(3) new Topinew Integer(2) new Bott)))) ootew Integer) At he abot Ditto ‘new Topinew Anchovy} ‘new Bott) ritnew Anchovy())? st No problem, This, too, emuves 3 aud hows new Tepinew Anchovy) the other layers alone new Topinew integer(3) new Topinew Anchovy) new Topinew Zero) new Topinew Zero|) sew Bot))}) new Bott))) emnew Integer) Chapter 5 What isthe value of new Topinew Anchovy). new Top(new Integer(3) new Topinew Zero() new Bot()))) sem(new Zero\))? What's wrong with that? And why did't i? Always? Here is the version of Num? (including OneMoreThan) with its own equals. Define the new Zera variant abstract elass Num® {) ‘class OneMoreThan extends Num? { Non? preocso | OneMoreThantNam® 7) { | predecessor =} | Public boolean equals Objet 0) { i (0 instanceof OneMoreThan) return prodecesor equals ((OneMoreThan}o}* predecessor else return fale: } I Objects Are People, Too ops. The answer is new Top(new Anchovy). new Topinew Integer(3) new Top(new Zero) ‘new Bot()))) We expecte it to remoxe mew Zero) from the pizza. Because equals for NumPs ses Object’ ‘equals, which always produces alse as we discussed shove when we iteoduond equals Unless we define it anew for those classes ‘whose instances we wish to compare Adding equa to Zero is easy. We use instanceof to determine whether the consumed valle is 8 new Zero) [class Zero extends Num? { ‘Public boolean epuals|Object 0} { |, return (o instanceof Ze): } } But what is the smderlinng of ((OneMoreThan)o) about? Wouldn't it have been sufficient to write o.pralcessor"? No. What isthe type of 0? So what is o.predeessor? Correct. Whaat do we Know after 1has sletertined that [o instanceof OneMoreThan) Precisely. So what des ((OneMoreThan}o) ds? What is ((OneMoreThan} 0s type? Are o an ((OneMoreThan)o} inworchangenbe? 1s this complicate? Did yon al notice the predevssor ast {(OneMoreThan}o) predecessor) in equals for OneMoreThan? The fist one, predecessor. refers to th predeecssor field of the instance of OneNtoreThan oi which wu ate us equals Aad tit field aight not be a OneMoreThan Object, wecoreting to (Object 0) which is what declares the type of Nonsense We know that 0° type is Object ant tat it is au instancr of OneMoreThan, 1 converts the type of 0 from Object to (OneMoreThan, is type is OneMoreThan, aul now i mos ((OneMoreThan) 0} prederessor ‘The underlying object is the sane. But no, the two expressions are not interchangeable Tpocaese the former's type is Object. whereas the latter's is OneMore Than, Sone as been drinking to maul cow Hose do the tw ses of prrdversson lifer? Se the secu one, [(OneMoreThan) 0) perderesser refers to the priderasor fekd of the instance ‘of OneMoreThan consid by equals Chapter 5 Yes. Are these two objects equal? ” ‘Time for lunch? ” Did you have a good lunch break? [Now what isthe value of new Top(new Anchovy(), new Top(new Integer(3), new Top(new Zero(), new Bot()))) rem(new Zero())? And why? Do we always add equals to a class? Do we need equals when we want to substitute one item for another on pizza pie? Wiat is the value of new Topinew Anchovy), new Top(new Tuna) new Top(new Anchowy(), new Bot()))) substFish(new Salmoa(), rnew Anchovy())? What kind of values does substFish consume? Objects Are People, Too If they are similar to the same int, they are equal. But most of the time, they are not. ‘That's just in time Yes, thank you. Now we get snow Top{new Anchovy) ‘new Top(new lnteger(3) ‘new Bot()), whieh is precisely what we want Because equals now knows how to compare Num? No, only if we need it. Yes, we do, Tes the same pizza pie with all the anchovies replaced by salmon: new Top(new Salmont). new Top(new Tuna() new Top(new Salmon\). ‘new Bot())) Tt consumes two fish and works on PiePs. st And whit does it produ’? What iste value of new Top(new Integer(3) ‘new Topinew Integer(2) new Top{new Integer(3) ‘new Bot))) subst Tut(new lntegee(S) new Integer(3}) What kind of vanes dos substfat consume? Aud what docs it produce? We cat deine SubstFish? lass SubstFish” ( Pie forBt(Fih® n Fish® return nev Bot): | Pie forTop(Objet Pie Fish? Fah? 0) ( (orgs) return new Topl1:sulstFsk(1.0) che return new Top(t subst Fish): | , Deine Subst” Dia we forget the boring parts? Ie always produces « Pie® "Ae isthe sage pizza pie with all 8s replaced by bs now Topinew Integer(5) new Topinew Integer(2)- new Topinew Integer(5). new Bott)))) 1 conse oo Integers works on Pies We always produces 4 Pe. Tr pot fron SubstFishY so Substine”, we jst nied to sithnttate Fish® iy Integer ceserywhere and Fh by “Tat” nthe clase ‘xd metho! nines class Substint” { Pree forBot (Integer n.Integer 0) | return new Bot():} Pie! forTap( Object Pie? Integer Integer a) | HE (ocequas(t)) return new Top( s.r subst Tato} else return new Topi f.r:substfotlano})s} ) 7 Yes, bec there is obit a et ener version Hike Rem” Chapeer 5 ‘Yes, we call it Subst”, Define it "We substitute Object for Fish and Integer. class Subst” { Pie? forBot(Object n Object 0) { return new Bot(): } Pie® forTop( Object Pier, Object, Object 0} { If (o.equas(t)) return new Top(n.r-subst(n.0)) else return new Top(¢.r.subst(0.0)):} Now itis time to add the protocol for Subst? "The abstract partis obvious to Pie?. Here are the variants. class Bot extends Pie? { ie rem (Object 0) { return remFx.forBot(o); } Pie” subst{Object n,Object 0) { return substFn forBot(n,0}; } Pie? rem( Object) ( return remFn forTop( tr); } Pie® subst (Object n.Object 0) { return subtPn forTop( tro); } Objects Are People, Too abstract class Pie? ( Rem remBn = new Rem”) | Subst” substFin = new Subst) abstract Pie? rem(Object 0) Bo : ” That was some heavy Hiting, bstract Pie® subst (Object » Object 0): IDde@vef Si OCOUS sr oo) € & im iS Trrothoc i i on eS ols = ‘Are protocols truly boring? * We acted as if they were. But, of course they are not. We just didn't ‘want to spend mich time on them. Let's take a closer look at the last one we defined inthe previous chapter. abstract Pie? rem(Objct 0): abstract Pie? subt(Objectn Objet 0): What is the difference between rem and subst in Pie®? What js the difference between rem and subst in the Bot variant? What is the difference between rem and jaubst in the Top variant? Boring Protocols * Okay, here are the variants again, class Bot extends Pie? ( Pie? rem(Object 0) { return remPn forBot(o):} Pie? subst(Object n Object o) ( return substPr forBot(n.0}: } } | class Top extends Pie? ( Object | Pie ToplObject -.Pie? +r) { | tat: ren) Pie? rem (Object) ( |. _feturn rem forTentinoh Pie? subst(Object n Object 0) { return subst forTop( tino}: } * The first one consumes one Object, the second one consumes two. * Simple: rem asks for the forBot service from ‘emi and hands over the Object it consumes; subst asks for the forBot service from substFn and hands over the two Objects it consumes. * Simpler: rem asks forthe forTop service from remFn and hands over the field values ‘and the Object it consumes: subst asks for the forTop service from substFn and hands ‘ove the field values and the two Objects it A that is all there isto the methods in the tatiauts of « protocol Lot's ot create orn aod sustFin in the datatype abstract class Pie? ( abstract Pie? rvm(Rem remkn Object 0) abstract Pie? subst(Subst™ subst, Object, Object os | , Yew it is a straightforward trade-off Instead * so ling a rem Fa field and a subst fle to te latatype. we How have rem of subst conse sich ees, What kind of wales ae conse Dy em andl sub? Heze is ho it changes Top. class Top extends Pie? { Object 1 Pie® ToplOdject Pie” -r) tat rear} Pie svm(Rem® remFin Object 0) { return rem Fa.forTop( to): } Pie? subst(Subst™ subst Fn Object». Object 0} { return substPiforTop(t.r.no) } ) How dos it affect Bot? But rvimEW and substFn defines in the datatype are still abit mysterions * This looks like wn obviows modification, The tie rem atid subst now corse 8 rem Fn and n substFn, respectively: Can they still fil forBot and forTup, thee eurresponding, ‘The definition of the datatype sags that they are a Rem® anu a Subst”, respectively. And every Rem® defines forBot and for Tip, sod 0 dos every Subst” In the sae manner. We jst nee hae cach concrete method's deception of what i Consumes, The rest remains the name class Bot extends Pie? | Pa rem (Rem wenn Object 2) | return srmPn forBot(): } Pa vat Subst vuln Object Objet 0) ( return substFu.forBot(n,a): } } Chapter 6 ‘That's right. Nothing else changes in the" variants. Instead of relying on fields of the datatype, we use what is consumed. Like what? Where are they used? ‘Yes. Here is Rem’. ‘class Rem” { | Pie? forBot(Object o) { | return new Bot(); } He forte Obj Ben | Object 0) { Af (o.equals(t)) aatn en hao} as | Sturn new Tort romth b Modify Subst” accordingly. ‘What is this all about? Understanding is more difficult. The word this refers to the object itself How did we got here? Boring Protocols We still have some work to do. Consuming an extra value here also affects how the methods rem and subst are use. In Rem and Subst, the interesting parts for example ‘That takes all the fun out of it lass Subst” { Pie® forBot( Object. Object o} ( return new Bot): | Pie® forTop( Object ¢ Pie? r, Object'n, Objet 6} { If (o.equas(t) return new Top.rsubst( this lse return ‘new Top( tyr. subst(this.n.0)):} nso) ‘Yes, what about it. Copying is eas Which object? ‘The protocol is that rem in Bot and Top asks for the forBot and forTop methods of remFn, respectively. 8 Ho ces that happen? Correct. And now forBot and forTop can refer tthe object rem Has t Thats it. Tricky Why? What i the value of new Top(new Anchovy) new Top(new Integee(3). now Top(new Zero) ‘new Bot()))) remninew Rem”) new Zero(T)? Aut lowe does the underined part relate to velae we id there? Wot isthe value of new Top{new Integer(3) new Topinew Integer(2). new Top(new Integer(3) new Bet()))) subst new Subst”). new Integer). new Intoger(3))? 1 happens with remFn forBoll...) and remFnforTop(.-) respectively Ob, so inside the methods of Rem*, t stands for precisely that instance of Rem” that allowed us to use those tethuds in the first place. And that must mewn that chew wwe use rine (this...) in forTop. it tells rem to use the same instance over aga, Not relly, ust selfreferential Became this is Rem, adit is exactly what we need to complete the job, We did the same exanple in the precesting Chapter, and the result remains the same 1 creates a Rem? object, w to the remPa in the old Pie? 1 cortesponds We did the same example inthe precesting hapter, azul the result remains the sane Captor 6 ‘And how does the underlined part relate to what we did there? So what isthe underlined part about? Roady for the next protocol? How aout some ice cream? ‘Take a look at subst in Top and at forTop in Subst”. What happens to the values that they consume? Is the handing back and forth necessary? Here is a way to define Subst” that avoids the handing back and forth of these extra values. class Subst” { Object |] Object 0: Subst™ (Object -» Object -0) { Pie? forBot() { return new Bot(): } Pie” forTor(Object Pi? r) { LE (ooquals(0)) return new Top(nrsubst(this)) che [return new Torani) } Boring Protocols “Te ereates a Subst” object. which corresponds to the remFn in the old Pie®, ‘We changed the methods in Pie®, which means that we rust also change how itis used, Let's grab a quick snack, ‘Cappuccino ermch sounds great. The more coffe, the better, [Nothing really. They get handed back and forth, though forTop compates 0 tf ‘We don't know any better way, yet Wow. This visitor has two feds." cleus orth fon shh How do we ereate a Subst”? What does that do? How so the methods know that without consuming more values? ‘Olay. so how would we substitute all new Integer(3) with new Integer(S) in new Top{new Integer(3) new Topinew Integer(2) new Top(new Integer(3) new Bot())})? And if we want to substitute all new Integer(2) with new Integer(7) in the os all that mean we have to ebange the protocol, too?” sw Subst”(new Integer(S) new Integer(3)) Ie creates a Subst” whose methods kuow how se new Integer(5) for all ‘occurrences of mew Integer(3) in Pie? to substi ‘The values have now become fekds of the Subst” object to which the methods belong. They’ no longer nee to be conse We write new Top(new Integer(3). new Top(new Integer(2) new Topinew Integer(3). new Bott)))) subst(mew Subst ( new Integer(S). new Integer(3)). We write new Top(new Integer(3) new Top(new Integer(2)- new Top(new Integer(3) ‘new Bot))) substinew Subst™( new Integer(7). new Integer(2)) Of course, because the methouls sudst in the Bot aud Top variants conan omy one value Chapter 6 ‘That's right. Here ate the datatype and its Bot variant. Define the Top variant. | abstract class Pie? { [abstract Pie? rem(Rem” remF batract Pie” subst(Subst” subst} ) class Bot extends Pie? { Pie? rem(Rem? rem) { return remPn forBot() ) Pie? sult (Subst™ sibs) { return sibs forBot(): | | Is there anything else miss ‘What is the diference between rem and subst in Bot? What is the difference between rem and subst in Top? Can we eliminate the differences? ‘True, because substFn is just a name for a value we don't know yet. But how can we make the types the same? Boring Protocols * tu the Top variant. we still ned to hand over both # and 7 | class Top extends Pie” { |sejar® | Top(Object .£,Pie” -r) { | Pie® erm(Rem® remFin) { | “return temFo forTop!t.r) } | Pie subbed) ( | return sudstFn forTont tr: } ) We haven't defined Rem’ for this now protocol. But itis simple and hardly worth Not much. ‘The name of the respective values they consime and the corresponding types Not much, ‘The name of the respective values ‘they consume and the corresponding types It is ena to make them use the same names, It doesn't matter whethor rm is diel ax Pie? rem(Rem® substFn) { return subst forToplt.r): } Both Rem” anid Subst” are visitors that ‘contain the same method ames al those methods consume and produce the sane types of values, We ean think of them as ‘extensions of common abstract class a Yes! Do it! © Here itis Great job, except that we will use interface “* for specifying visitors like these. interface PeVisitor! { | Pie? forBot) Pie? forTop(Object tie? r): No. A class implements an interface; it does not extend it Now that we have an interface that describes the type of the values consumed by rem and subst, can we make their definitions even Correct, What is the difference between rem.“ and subst, now? What isa good name for this method? 9 | abstract class PieVisitor® { [| abstract Pie® forBot(): | RRotract Pie? forte Object Pe 7) t Okay, that doesn’t seem to be a great difference, Can a class extend an interface the way it extends an abstract class? Fine Yes, we can. Assuming we ean use interfaces like abstract classes, we can Pie? rem(PieVisitor™ poFn) { return prFn.forTop(t.): } and Pie? subst(PieVisitor” poFn) { return prFn forTop(t.}: } in Top. ‘There isnt any, We ean ase the same namie for both, as long as we remember to use it whenever we would have used rem oF subst. ‘The method accepts a visitor and asks for its services, so we call it accept Chapter 6 And what is a better name for pon? [Basy: ask, because we ask for services. Now we can simplify the protocol. Here is the new Rem! class Rem” implements PieVisitor! { Object Ren (bo ( Pie? forBot() { return new Bot): } public Pie® forTop(Object Pie? r) ( lo.equalsit) return raceep(this): else | return new Top(ér-cccet( this): } Supply the protocol Did you notice the two underlined ‘occurrences of publie? When we define a class that implements fan interface, we need to add the word Public to the eft of the method definitions. It’s a way to say that these are the methods ‘that satisy the obligations imposed by the interface. Correct, ‘They are just icing. Boring Protocols 7 "Here we go. lscearemercel | abstract Pie” accept(PieVisitor” ask); } | class Bot extends Pie? { Pie? accept(PiVisitor! ask) { | return ask forBot():} } | class Top extends Pie? { Object f: Pre? | Top(Object Pie? -r) { tat res) Pie? acorpt(PieVisitoe” ask) { | return ask forTop(t.r);} } Yes, what about them? Why? Looks weird, but let's move on, Olay, we still won't forget them, [Nowe define the new Subst”, Here itis class Subst” implements PieVisiter! { Object: Object 0: | Subst” (Object -n, Object -0) { | o=.0') Dublic Pie® forBott) { return new Bot); ) public Pie? forTop( Object Pie? +) { if (equals) return new Top(n.raccept(this)} clse return new Top(¢.raccept(this));} Draw a picture ofthe interfuee PieVsitor? Here is our picture. And all the classes: Pie, Bot, Top, Rem”, and Subst” Pie? (ee) os Why is there is a Subst” to PreVist not an arrow, fom it doesn’t extend it. Arrows mean “extends.” Hines mean “implements.” ‘And the dashed line? Ie tell us the mame ofthe method that connects the datatype to the visitors 4 Chapter 6 What is the value of Easy: new Top(new Anchovy) new Top(new Salmon) new Top(new Tuna(), new Top(new Tuna(), new Top(new Anchovy), ‘new Top(new Salmon). new Top(new Tuna(), ‘new Top(new Tuna(), new Top(new Anchowy(), new Top(new Anchovy|), new Bot())))) new Bot())))) caccept(new LtdSubst”(2, ‘new Salmon), new Anchovy()))? Explain what LtdSubst” produces.” "The methods of LidSubst” replace one fish on ‘pie by another as many’ tines as specified Atte mmeiebntetstetin an tat shew by the fist valve consume hy LedSubst™ Good. Define LedSubst”. "That's ery, We have such a flexible protocol that we only need to define the essence now: class LtdSubst” implements PieVisitor” { int ¢: Object Object 0: LedSubst”(int -c Object _» Object -0) { ob public Pie? forBot() { return new Bot) public Pie? forTop(Object Pie”) { if (c= 0) return new Top.) cle Sf (o-ouale(t) return new Top(n.racept (this); tse retarn now Top(¢..acerpt(this)): } Boring Protocols 95 ‘What isthe value of ‘new Top(new Anchovy) ‘new Top(new Tuna(). ‘ew Top(new Anchovy) ‘new Top(new Tunal). new Top(new Anchovy() ‘new Bot()})))) saceept{new LteSubst”(2, ‘new Salmon), new Anchovy()})? Why doesn’t ¢ ever change? (Cam we fix this? If e stands forthe current count, how do we create & LtaSubst that shows that we have jst substituted one fish by another. Oops, there are too few anchovies on this pizza pie ‘new Top(new Salmon() ‘new Top(new Tuna(), ‘new Top(new Salmon(), ‘new Top(new Tuna() sw Top(new Salmon() ‘new Bot))))) Because ¢, the counting eld, never changes Because this, the LtdSubst” that performs the substitutions, never changes. We can’t ch this with a change wge this, but we ean replace sw Ladue” that reflects the Simple, we use new LtdSubst”(e~ 1.0) place of this, ‘The Sixth Bit of Advice When the additional consumed values change for a self-referential use of @ visitor, don't forget to eveate a new nisitor Chapter 6 Define the new and improved version of LedSubst” How does this ier from, new LtdSubst”(e~ 17,0)? How do you feel about protocols now? Boring Protocols jlements PieVistor” { intr Object _n Object -o} ( Public Pie? forBor() { ‘return new Bot): | public Pie? JorTop(Object Pie? ») ( if(e == 0) return new Top(t.r: lse iF (o.eqats(t)) return | “new Toon. | nace new LiaSubst( Ln.) lse return ‘new Top accept this)):} ‘They are two different LedSubst™s. One replaces ¢ occurences of o by 1 in 8 pia pie, and the other one replaces only ¢~ 1 of them. They are exciting, Lets do more o 6 Yes new Flat(new Apple) new Flat(new Peach() ‘new Bud())) flat Tree? 5 * Yas itis nlso a flat Teee?. new Flat(new Pear() new Bud()) flag Tree?” And how about * No, it is split, s0 it can't be fat new Splt( ‘new Bud(), new Flat(new Fig) new Split, new Bud(), new Bud())))? Here is one more example * No, int ta thee new Spit( new Spit new Bud), new Flat(new Lemon) new Bud())- new Flatnew Fig), new Spit( ‘new Bud) sew Bud) Init fat? Is the difference between flat trees and split * Unless there is anything else to Tree®, it's trees obvious now? totally clear Good, Then let's move on, * Olay: let's Oh My! Here ate some fruits [abstract class Frat? {) [class Peach extends Fruit? { |" publie boolean equals(Object 0) ( ‘return (o instanceof Peach): } class Apple extends Fruit? { public boolean euals(Object 0) { return (0 instanceof Apple): } } It does not differ too much from what we Ihave seen before abstract clas Te? () | a —_ [ines Flt extends Tree? { | Fruit? fs Tree? 1 Flat(Fruit? JTree” .t) { class Pear extends Fruit? { Public boolean equals(Object 0) { ‘return (0 instanceof Pear); } D ‘lass Lemon extends Fruit { ‘Public boolean yuals(Object 0) ( ‘return (o instanceof Lemon}: } } ‘lass Fig extends Frit? ( Public boolean ezuals(Object 0) { return (0 instanceof Fig); | ) Let's say all Trees are either at, split, or bud. Formulate a rigorous description for Trees Did you notice that we have redefined the ‘method equals in the variants of Fruit?” Do Tree? variants contain equals? 100 class Spit extends Tree? { Tree? | Te? Splt(Teee? Tree? +r) { ti | — | * ‘That probably means that we will need to ‘compare fruits and other things No, which means we won't compare them, but we could, Chapter 7 How docs the datatype Tree? differ from all" The name of the new datatype occurs twice the other datatypes we have seen before? _inits Split variant. Lets add a visitor interface whose methods "That just means extending what we have produce booleans with one method eac = [class Bud extends Tree? ( [boolean forBud() boolean accept(bTeeeVistor! ast) { boolean forFlat(Fruit? f Tree? #); return oskforBud(): } boolean forSplit Tree? 1.Tree? ) pe J [interface bTreeVisitor™ { [class Flat extends Tres” { Here is the new datatype definition, Frut® f; — Tree? t: abstract class Tree? { Frat(Fruit? -f.Tree® 1) ( boolean accept (bTreeVisiter? ask) ey | abstract | oe | } "boolean accept (bTreeVisitor! ask Revise the variants, pt d{ return ast forFlat(f.t): } ) ‘lass Split extends Tree? { Tree? I Tree? Split(Tree” Ties” 1) { 4 boolean acep( Tees ak) ( turn ost forSi(t)} | But isn't bTreeVisitor™ @ pretty unusual Yes, itis, Hang in there, we noed unusy ‘names for unusual interfaces. Here b reminds tus that the visitor's metheds produce booleans. Oh My! 01 How many methods does the definition of bisFlat™ contain, asning i implements DTreeVistor!? What type of values do the methods of bisFlat” produce? What visitor does blslat” remind ws of? Here is a skeleton for blsFla®. "class bisFiat” implements BTreeVistor” { public boolean forBua) { | return} public Doolean forFtal(Faut? JTree? #){ publie boolean forsplit( Tree? I Tree® r)( return} | , Fill the blanks, Define the bisSplit” visitor, whose methods cock whether a Tree? is constructed with Split and Bud only ‘Three, because it works with Trees, and the datatype definition for TreePs his three * booteans. OnlyOnions*. That's easy now “class bsFlt” implements BTreVistor? public boolean forBudl) return te} | pub boolean forFta( Fruit? f-Tiee® #)( return (neeeptthis):} | pubic ‘boolean forSplirTeee? 1 Tree” »)( return false, } ) Hee isthe easy part lass bsSplit” implements bTeeeVisitor® { public ‘boolean forBudl) { return tue: } public ‘boolean forFlat(Fruit” f.Teee? #) { return false: } public ‘boolean forSplit(Tree? 1.Tre »} ( Chapter 7 ‘What is dlfcult about the last ine? Isn't that easy? [And then? 1" accept (this) Is tre, do we need to kn ‘accept(this) whether i Laccept(this) is false, do we need to know whether raccept(this) Finish the definition of bisSpit” using itt.) return else return Oh My! We need to check whether both [and ne split ‘Yes, we just use the methods of bisplit” on J and ‘Then we need to know that both ate tr. Yes, because IF both are true, we have a split tree, No, then the answer i fale Now we can di ‘lass blsSplt™ implements bTreeVisitor® ( public bboolean forBud() { return true: } public boolean forFlar(Frut® Tree? ¢) { return false: } public boolean forspit(Teee” Tree” r) { If (Lacoept(this)) return ¥-2ceept(this): se false: ss Give an exatnple of a Tree” for whieh the“ There is trivial one methods of bIsSplit™ respond with true. new Bud() How about one with five uses of Spit? Here is one new Split( new Splt( ‘new Bud(). new Split, ‘new Bud) new Bud) new Split ‘new Bud(), new Split new Bud(), new Bud) oes this Teee? have any frit? No, Define the bHasFruit” visitor. © Here itis | class bHasFrvit™ Implements bTreeVistor! ( public | boolean forBud() { | return false: } public boolean forFlat(Fruit? JTree? ¢) { | return tue: } public ‘boolean forsplit( Tre” 1-TreeP +) { if (Laceept(this)) return tae: else. | return saceept(t 104 Chapter 7 What is the height of new Splt( new Split( new Bud), new Flat(new Lemon), ‘new Bud())) new Flat(new Fig), new Split new Bud(). new Bud())))? ‘What isthe height of 2 now Splt( ‘new Bus), new Flat(new Lemon) ‘new Bus()))? What is the height of 1 new Flat(new Lemon(), new Bud())? What is the height of new Bud()? So what isthe height of a Tree?? * Just as in nature, the height ofa tre isthe distance from the beginning to the highest Youd in the tree. Do the methods of Height” work on a Teee?? "Yes, and they produce an int. Is that what the iin front of Height is all“ Tt looks like i stands for int, doesn't it? about? Oh My! 105, What isthe value of new Splt( new Split( ‘new Bud(). new Bud()), new Flat(new Fig) new Flat(new Lemon). new Flat(new Apole). new Bud())))) ccept( new Height”)? Woy isthe height 4? And how do we get from 3 t0 4? U picks the larger of two numbers, x and y. iHeight?*s methods measure the heights of the Tree?s to which they correspond. 108, Because the value of new Spit, new Bud) new Bud()) aaccept{new iMeight™()) Is 1: the value of, new Flat(new Fig(), new Flat(new Lemont). new Flat(new Applet), new Bud()))) caccept{new iHeight™()) is 3; and the larger of the two mmbers is 3. We need to add one to the larger of the urmbers so that we don’t forget that the ‘original Tree? was constructed with Split and those two Trees Ob, that's nice. What kind of methods does iHeight” define? ” Now that's problem, Chapter 7 Why? So what? Okay, so let's define a visitor interface that produces ints. ‘Yes, and once we have that we can add another accept method to Tree? = =o) aeaEaeae] abstract class Tree? ( | abstract boolean accept(bTreeVisitor? ask); abstract int accept(TreeVisitor? ask) } We can have two methods with the same ‘name in the same class as long as the types of the things they consume are distinct ‘Ada the new accept methods to Tree?” variants, Start with the easy one Oh My! ‘We defined only interfaces that produce booleans in this chapter. ‘The methods of Height” produce ints, which are not booleans, * Tes almost the same as bTreeVisitor™ [interface iTreeVisitor™” { int fora int forFlat(Feut® f Tree? 0) 3 forSpit Tree? UTree? 1) oes that mean we ean have two methods ‘with the same name in one class? ‘TreeVisitor, so we can have two versions of ‘cept in Tree”. class Bud extends Tree? ( boolean accept(bTreeVisitor! ask) { return astforBud() } Int accept(TreeVisitor? ask) { | return ask forBudi); } | pb 107 ‘The others are easy, too. We duplicate accept [tas Fat extends Tes? | Fat? f Tree? t | Flat(rrait™ f.Teee? 1 { | f ) tacky | Bootean accpeTenvitor” ot) {| | return ask forFlat(f,t); } int accept(iTreeVisitor™ ask) { return ask forPlat(f,t); } } Here is Height Public int forBud() { return | | public int forFlat(Fruit? f.Tree” «) (| | Preturn pbc it forSpit(Tee? (Tee? 1) (| | return i} Complete these methods What is the value of ‘new Spit new Bud) sew Bud()) acerpt{new iHeight™()? And why is it 1? We must also change the ¢ype of what the new accept method consumes and produces. | clase Spit extends Tree? { Tree? Tree? | Spletiee? Tree? -r){ | te | tea or} faeces sen ne EEE | ootean acxept(TieeVisitor™ wat) { return ask forSpit(lr)} Int aceeptiTieeVisitor? ask) { return ask forSplit( lr): } Bo ‘That's easy now ‘lass Height” implements iTreeVisitor” { public int forBud() { | “return 0: } public int forFlat(Fruit® f.Tree” ¢) { return t.accept(this) + 1: } | public int forSplit(Teee® 1,Tree? 1) { return, (Laceept(this) Li r-aceept(this)) +) ) 1, of course, Because new Bud). accept (new iHeight™()) is 0, the larger of O and 0 is 0, and one more ist Chapter 7 What is the value of new Split( new Spit new Flat(new Fig() new Bud()), new Flat(new Fig) new Bud())). new Flat(new Fig() ‘new Flat(new Lemon() new Flat(new Appl), new Bud()))) accept ‘new tSubst”( new Apple). new Fig()))? Correct. Define the tSubst” visitor. What's the problem? Good job, How nbout the datatype Teee®. Oh My! If the visitor tSubst” substitutes apples for figs, here is what we get: new Split ‘new Splt( new Flat(new pele) ‘new Bud()) new Flat(new Apple) ‘new Bud())). new Flat(new Apple) ‘new Flat(new Lemont). new Flat(new Apple) ‘new Bud()))) Its lke SubstFish” and Substoe” from the fend of chapter 5, but we can't da it just sot Its methods produce Trees, nether ints nor ooleans, which means that we need to add yet another interface Interface tTreeVisitor { Tree? forBud() | ‘Tree? forFlat(Fruit® Tree? ¢) Tree” forSplit(Tree? 1 Tree” +); } * Basy, Here is the abstract one abstract class Tree” { act oolean accept (bTreeVisitor? ask) | abstract int accept(iTreeVisitor™ ask); | | abstract Tree” accrpt(tTreeVisitor® ask); Lb Define the variants of Tree?. * No problem, class Bud extends Tree? ( | boolean accept (bTeeeVisitor! ask) { return ask forBud\): } int accep iTeeeVisitor? ask) { return es. forBud(): } Tree? accopt(tTreeVsitor™ ask) { return ast forBud(): ) ) class Flat extends Tree” { Fruit? f Tree? 4 Fiat(Frut f,Tree? -t) { | boolean accept(bTreeVistor! ask) { return ast forFlat(f.t);} int accept(iTreeVistor? ask) { return ast forFlat(f.t), } Tree? accept(tTreeVisitor# ask) { return ast forBlat(f.t):} class Split extends Tree? { Tree? t, Tree? Split(Tree Tees? 1) { tat Doolean arept(bTreeVistor™ ask) ( return ask forspl(l) } Aint corp eestor” ask) { return ask frspli(l): } \ Tree? accept(eTeeVisitor! ask) { return ask forsplall) } Lb no Chapter 7 ‘Then define tSubst™ Here is. Tree? that has three Fig new Split new Spit new Flat(new Fig(). new Bud) sw Flat(new Fig() 1ew Bud()))- new Flat(new Fig(), new Flat(new Lemon(), new Flat(new Apple). ‘new Bud()))) Now define Occurs”, whose methods count how often some Fruit? oceurs in a te Oh My! That's easy. 10, It has two fees, one for the new Fruit? and one forthe old one. and the rest is straightforward. {class eSubst” implements eTeeeVistor { Fruit? n: Frit? 0 ‘Subst (Frat? > -lievisior? Bot Top Subst Subst” |] [LedSubst” No, but the picture eaptutes the important" Fine relationships Is it also possible to define LtdSubst” as an extension of Subst”? ‘counts as it substitutes If LedSubst” is defined as an extension of "As we just said, ¢ isan addition and for Top Subst”, what has to be added and what has is different to be changed? ‘The Fighth Bit of Advice When extending a class, use overriding to enrich its functionality, Like Father, Like Son 135, Here is the good old definition of Subst from chapter 6 one more time, ‘Object: Object o ‘Subst (Object -n,Object 0) { on} Public Pie® forBor() { return new Bot(): } Public Pie” forTop( Object Pie? r) { if (o.equals(¢)) new Top(n.raccept(this), Let's draw a picture lass Subs” implements PeVistor” { * The rest follows naturally, just as with the ‘evaluators and the previous version of these to classes ‘lass LtdSubst” extends Subst” { int: | LedSubst” (int -c Object .n Object -0) { | super a-2} public Pie? forTop(Object Pie? +) { if(c==0) return new Top(‘,7) else If (o.equals(t)) return new Top(n, accept new LtdSubst”(e— 1.n.0))) else return, new Top(t,r.accept(this)}; } Fine, and don't forget to use lines, rather n arrows, for implements. accept m PieVisitor™ Subst” You deserve a superdeluxe pizza now. LedSubee” tes already om its way” Chapter 8 - ®e Remember Point?” If not, here isthe datatype with one additional method, minus We will talk about minus when we ned it, Dut for now, just reall Point's variants. abstract class Point? ( int 3 int y. | Pont int int 2) { y=} boolean cloverT0{Point? p) { return distaneeToO() < p.distanceToO() } Point? minua(Poin® p) { return new CartsianPt(e — pry pa): } | abstract int divtanceTo0\) iD Good. Take a look at this extension of ManhattanPt class ShadomedManhattanPt ‘extends ManhattanPt { int A, int 3, ShadowedManhattanPt(int | int -y | super.distanceToO() + Ae + Ay: } ) ‘What is unusual about the constructor? Be a Good Visitor * Te has been a long time since we discussed ‘the datatype Point® and its variants, but they are not that en fo forget |class CartesianPt extends Point” { ConesianPtint int) super} int distanceToOQ) ho owl) class ManhattanPt extends Point” { ManhattanPtint int) ( supers) | int distonceToOQ) { | reams) Buses A, By 4, = Dy in addition to super(-1.-). ‘And what does that mean? (Okay. So what is @ ShadowedManhattanPe? Is this a ShadowedManhattanPt: new ShadowedManhattanPt(2,31,0)? What is unusual about distanceToO? Here, super.distanceToO refers to the method definition of distanceToO that is relevant in the class that ShadowedManhattanPt extends Correct, But what would we have done if ManhattanPt had not defined distance oO? ‘Yes, and so on, What is the value of new ShadowedManhattanPt(2,31,0) distance TOO()? 140 By using super on the fist two values ‘consumed, the constructor ereates a ‘ShadowedManhattanPt with proper = and y fields. The rest guarantees that this newly ‘created point also contains values for the two additional fields, It i a ManhattanPt with two additional fields: A, and Ay. These two represent the information that determines how far the shadow is from the point with the fields x and y: Yes Unlike any other method we have seen before, it contains the word super. So far, wwe have only seen it used in constructors ‘What does it mean? Okay. That means we just add x and y when ‘we evaluate super. dstanceT0O(), ‘Then we would refer to the definition inthe class that ManhattanPt extends, right It is 6, because 2 + 3 is 5, and then we have to add 1 and 0 Chapter 9 Precisely. Now take look at this extension ‘of CartesianP. class ShadowedCartesianPt ‘extends CartesianPt ( int | int Ay) { super(.2-v) | ne anmeiio0 | "return super distanceT0O() i nccerU ) | int -A,, | | What is unusual about the constructor? Is this « ShadowedCartsianPt ‘now ShadowedCartesianPt(12,5.3,4)? ‘And what is the value of ‘new ShadowedCartesianPt(12.5,34) distance TOO)? What do we expect? Be a Good Visitor " Nothing. We just discussed this kind of constructor for ShadowedManhattanPt Yes. Te 18, because the distance of the Cartesian point (125) is 13, and then we add 5, because that i the value of VSR with A. replaced by 3 and Ay replaced by 4 17, obviously. ait Why 17? We need (0 ald A, to z and Ay to y when swe think of a ShadowedCaresianP. oes this explain how distanceTo0 should Ineasure the distance of a ShadowedCartesianPt to the origin? Revike the definition of ShadowedCartesianPt according: Do we still need the new CaresianPt after distanceToO has deterinined the distance? ivy "Because we need to think of this point as ii new CartesianPt(15.9) "And indeed, the value of new CartesianPt(15,9) distanceT0O() 17, "Completely. It should make » new CartesianPt by adding the corresponding fields and should ther measure the distance ‘of that new point to the or Ohay class ShadowedCartesianPt ‘extends CartesianPt [ int 4, int Int distance ToO() { return new CartesianPt(s + Qey + Ay) distance ToO(): } No, once we have the distance, we have no tice for this point. Chapter 9 Correct. What is the value of true, ‘new CartesianPt(3.4) Dbecause the distance ofthe CartesianPt to ‘closerToO( the origin is 5. while that of the ‘new ShadowedCartesianPt(15,1.2))? ShadowedCartesian®t is 7. How did we determine that value? * That's obvious Is the rest of this chapter obvious, too? = What? ‘That was a hint that now isa good time to” Oh, Well, that makes the hint obvious, take a break Come back fully rested. You will more than” Fine need it Are sandwiches square meals for you? * They can be well-rounded, Hore are circles and squares © Then this must be the datatype that goes = = = with it class Circle extends Shape? { nw sanp int abstract class Shape? { Citcle(int -r) { abstract i) boolean aceept(ShapeVisitor” ask); a } SenleananapSnpeiir ast { are =r __| [class Square extends Shape? ( int Squarefint 3) ( i} | boolean accept(ShapeVisitor™ ask) { 1 Fearn okra | Be a Good Visitor 143, Very good. We also need an interface, and“ Te suggests that there is another var here iis Trans. | interface ShapeVistor” ( boolean forcrete( int) boolean forsmare (nt) boolean forTrans(Point” q.Shape” s); | i | ‘Yes and we will need this thi now this looks pretty straightforward ‘what's the point? [ange Tan! extends Shape? ( Point? 4; Shape? | Trans(Point” _g.Shape? -s) { | f a Tee | oe Let's create a circle * No problem: new Circle(10} How should we think about that cicle? “We should think about it as a cizele with radius 10, Good. So how should we think about © Wott, that's a square whose sides are 10 units new Square(10)? Ton, Where are our citcle and square located?” What does that mean? a Chapter 9 ‘Suppose we wish to determine whether some CartesianPt is inside ofthe circle? ‘And how about the squae? Pick one ‘That will do. Is the CartesianPt with = wee 10 al cutie) 10 eke sauate? [And how about the Are all circles and squares located at the origin? ‘This is where Trans comes in. What is new Teans( new CartesinPt(56), ‘new Cirle(10))? How do we place a square's southwest comer at new CartesianPe(5.6)? Is new CartesianPt(10,10) inside either the circle or the square that we just referred to Be a Good Visitor In that case, we must think of the circle as being drawn around the origin. ‘There are many ways to think about the location of the square, Lets say the square's southwest corner sits fon the origin, Yes itis. but barely Certainly not, because the crce's radius is 10, but the distance of the point to the origin is 14, ‘We have no choice so far, because Circle and Square only contain one feld each: the radius land the length of a side, respectively ‘Aha. With Trans we can place a circle of radius 10 at a point like new CartesinPr(5 6). Also with Trans: ‘new Trans ‘new CartesianPt(5 6), new Square( 10} “Is inside both of them. M5 How do we determine whether some point is” inside a circle? How do we determine whether some point is. inside a square? Is that all? Aren't we om a roll? Let's take look at our circle around new CartesianPr(5.6) ‘again. Can we think of this point as the origin? By how much? How could we translate the points by an appropriate amount? Is there a method in Point? that accomplishes that? M6 If the circle is located at the origin, itis simple. We determine the distance of the point to the origin and whether itis smaller than the radius If the square is located at the origin, i is simple. We check whether the points ‘coordinate is between O and s, the length of the sde of the square. No, we also need to do that for the y coordinate We have only done the easy stuff far. This not clear how to heck these things when the circle oF the squage are wot located atthe origin, We can if we translate all other points by: an appropriate amount. By 5 in the x direction aad 6 in the y direction, respectively We could subtract the appropriate ausount from each pot Yes. Is that why we included mines in the ‘new definition of Point?” Chapter 9 Indced, And now we can define the visitor“ “The three methods put into algebra what we HasPt®, whose methods determine whether just discussed some Shape? has a Point? inside of it ‘lass HasPt” implements ShapeVisitor” { Point® »: HasPt?(Point? .») { ip Ea Public boolean forCivel(int r) { return p.distanceToO\) < 1: } public boolean forSquare( if (par <) | “return (ny <9): else return false: } | | publie | “boolean forTrans{Point® aShape® s) { | return saceept | new HasPt™(p-minus(q)))s} BO See Fo ‘What is the value of “We said that this point wasn’t inside of that ow nl Cis he sve fe accept ‘new HasPt” (new CartesianPt(10,10)))? Good. And what isthe value of tre, new Square(10) accept ‘new HosPt” (new CartesianPt(10,10)))? Let's consider something a bit more We already considered that one, 100, The ineresting. What is the value of value is tue, because the cirele’s origin is at new Trans( new CartesianPr(5.6) new CartesianPt(5 6), new Cirele(10)) accept new HasPt” (new CartesianPt(10,10)))? Be a Good Visitor ur Right. And how about this: ‘new Trans( new CaresianPU(5.4), new Trans( ‘new CartesianPt(5.6) ‘new Cirle(10))) accept ‘new HasPt” (new CartesianPt(10,10)))? But what is the value? And then? Very good. Can we nest Trans three times? Ready to begin? No, The exciting part is about to start. How can we project a cube of cheese to a piece of paper? [And the orange on top? 18 [Now that is tricky. We used Trans tice, ‘whieh we should have expected given Trans's definition First, we have to find out whether new Trans( new CartesianPt(5 6), new Cicle(10)) aceept( new HasPt" (new CartesianP1(5.6))) is tue oF false, Second, we need to look at new Circle(10) cept ‘new HasPt (new CartesianPr(0.0)). tout the value of this is obviously true, ‘Ten times, if we wish, because Trans contains a Shape?, and that allows ts to nest things as often as needed, What? Wasn't that it? © We are all eyes 1 becomes w square, obviously: A circle, Transed appropriately. Chapter 9 ‘Can we think of the two objects as one? Here is our way. a. class Union extends Shape” { | Shape? | Shape? Union(Shape® s.Shape” 1) { eee boolean accept(ShapeVisitor? ast) { return; } Bo What do we know from Cree, “Trans about accept? So what should we do now? “ Correct, except that we won't allow ourselves to change ShapeVisitor! Just to make the problem more interesting, Be a Good Visitor We can, but we have no way of saying that a circle and a square belong together. ‘That looks obvious after the fact. But whys there a blank in accept? We know that a ShapeVisitor” contains one ‘method each for the Ciecle, Square, and Trans variants. And each of these methods consumes the fields of the respective kinds of objects We need to change ShapeVisitor” so that it specifies a method for the Union variant in addition to the methods for the existing Wiy can’t we change it? “In that case, we're stuck 140 We would be stuck, bt fortunately we ean ‘extend interfaces. Take a look at this ‘extends ShapeVisitor ( boolean forl'nion(Shape? s,Shape? 1) } Basically! This extension produces an interface that contains all the obligations (i.e. names of methods and what they cousume and produce) of ShapeVisitor® and the additional one nataed forUnion nc ca cat xn sera Yes it should, but becuse UnionVisitor! extends ShapeVisitor itis also & ShapeVisitor! Perfect reasoning. Here is the completed ds ‘lass Union extends Shape” { | Shape? Shape® t Union(Shape® -s,Shape® .*) ( \ tn} esas core ot) (| return | {(UnionVisiter!)ask)forUnion(s.}:} ee ” Which means that we extend i way we extend classes, Does that mean accept in Union should receive a UnionVisito™, so that it can use the for'nion method? “We have heen here before, Our accept tmethiod aust consume a ShapeVisitor! and fortunately every UnionVisitor™ implements a ShapeVisitor!, too. But if we know that ‘arp! consumes & UnionVistor, we can couvert the ShapeVisitor' to a UnionVistor? anu invoke the forUnion method. And it mnkes complete sense. Chapter 9 Let's ereate a Union shape. ‘That's an interesting shape. whether new CartesianPr(12.16) is inside? Could it be a UnionVistor”? Define UnionHasPt”, which extends HasPe” with an appropriate method forUnion oes UnionHasPt” contain forUnion’? Be a Good Visitor That's trivial "Here it i. Tes method checks wheth new Trans( new CartesianPr(12.2), new Union( new Square(10) new Trans( new CartesianPt(4.4). new Cirel(5)))). Should we check” We can’t. HasPt” is only a ShapeVisitor it §s not a UnionVisitor! No. It does not provide the method fortinion the point isin one oF the other part of a ‘The other methods eome from HasPt | class UniontiasP” extends HasPr” { UniontasPe* (Point? ShapeVisto™ newHlasPH(Poit™ p) ( return new HasPt” (9); public boolean forCircle(int °) { return pudistanceToO() < ri) public boolean forSguare(int 5) { if (pz < s) oo (py ss) | return tbe: pubes Dosean jorrns(Pain® oShape”») wetsen s-accept(newHasPt(p-minus(q))) } How does this definition differ from the previous one? Good. What does neuwHasPt produce? A now ShapeVisitor™ x its interface implies, ‘And how does it produce that? "By construeting a new instance of HasPe Is neuHlasPt like a constructor? "This virtually indistinguishable from a constructor, whichis why itis above the line that separates constructors from methods. Be a Good Visitor 135 Does that mean the new definition of HasPe? tnd the previous one are really the same? Very well, But how doos that help ws with four problem? Cam we override newHasPt when we extend Hasbe”? Lot's override newflasP? in UnionHasPe” That's true. Should it produce a UnionHasPe” wwe, Should we repeat it? HasPt? or a" ‘They are mostly indistinguishable. Both forTranses, the one in the previous and the ‘oue in the new definition of HasPt”. produce the same values when they consume the same values ‘That's not obvious, Yes, we can override any method that we ‘wish to override When we override it, we need to make sure it produces a ShapeVisitor! The latter. Then forTrans in HasPt® keeps producing a UnionHasPt?, if we start with UnionHasPr? Let's just roread it ‘The Ninth Bit of Advice fa datatype may have fo be extended, be forward looking and use a constructor-ike (overrdable) method so that vistors can be extended, too Chapter 9 [And that's exactly what we need. Revise the '”” definition of UnionHasPt * the an nance of efor mato pttern If we assemble all this into one picture, what “* do we get? ‘Shape Here itis, ‘lass UrionHasPe? fextendls HasP2” implements UnionVisitor ( UniontasPe” (Point? -p)( super(p. ShapeVistor” newtasPr(Point™ y)( return new UnionHasP0™(p) } Public ‘boolean forUinion(Shape” s,Shape™ £){ if (s.acept(this)) ‘return tee: | else ‘return taccept(this): } [A drawing that helps our understanding of the relationships among the elasses and interfaces ~~ = all ShapeVisitor™ Circle Trans, What does the bex mean? Be a Good Visitor Everything outside of the box is what we designed originally and considered to be ‘unchangeable; everything inside is our 187 Does the picture convey the key idea ofthis chapter? Is anything missing? Lets see whether this definition works. What isthe value of new Trans( ‘new CartesianPt(3.7) new Union( ‘new Square(10), new Cirle(10))} aceept( ‘new UnionHasPt™( new CartesianPr(13,17)))? Which method should we use on it?” Whereis forTrans defined? So what should we do now? What is this? And how does that work? 158 "No, It does not show the addition of a ‘onstructorlike method to HasPt” and how it is overridden in UnionHasPt”. Square, but that’s olay We remember that the shape was built with Trans. forTrans, of course Ie is defined in HasPL”. We should determine the value of ‘new Union( new Squate(10), new Cirele(10)) acoept( this newHasPL( new CartesianPt(10,10))) "The current visitor, of course ‘We determine the value of, this. newlfasPe( new CartesianPt(10,10)) and then use accept forthe rest. Chapter 9 ‘And what do we create? What is the value of new Union( new Square(10), new Cicle(10)) saccept{ ‘new UnionHasPt™( new CartesinPt(10,10)))? How do we do that? Is it tue? ‘Are we happy now? Is it good to have extensible definitions? Very well. Does this mean we can put together flexible and extensible definitions if ‘we use visitor protocols with these cconstructor-like methods? ‘And why is that? Are you hungry yet? Be a Good Visitor ‘The new UnionVisitor™ new UnionHasPt™( new CartesianPt(10,10)) Unions? alao satisfies the interface ShapeVisitor”, so now we can invoke the fortinion method We first determine the value of new Square(10) accept ‘new UnionHasPt™( new CartesianPt(10,10))} Ii is tre, we're done, It i. So we're done and we got the value we expected, Ecstatic ‘Yes. People should use extensible definitions if they want their code to be used more than Yes, we can and should always do so Because no program is ever finished. ‘Are our meals ever finished? 139 of LO. Tae. Siar “2 “2 Have you ever wondered where the pizza pies " come from? Mere is our pizza pieman clas Pieman" implements Pieman® { Pie? p = now Bot): [pute it eden bic 0 ( P= new Topl tp) return occTop(t): } public int remTop( Object ¢) { [P= Pe inecptinew Ran) | return oceTop(th: } public ing sutstTop( Object n,Object 0) ( P= (Pie”)p.accept(mew Subst”(n,0)) return oceTop(n}: } public int oe Top( Object 0) { return ntegerp-ecent new Occus¥(0)) ‘ntVatuel b | ow so? Haven't we seen Pie®, Top, and Bot ” before? And haven't we seen visitors ike Rem’, Subst”, and Occurs” for various datatypes? Let's not worry about them for a while. The State of Things to Come ‘You should have, because someone needs to make the pi. * This is beyond anything we have seen before. ‘We have seen them * Yes, yes. But what are the stand-alone semicolons about? * Pine, but they are weird 161 Here is the interface for Pieman-" interface Piemané { int add Top Object ¢) int rem Top Object ¢) int subst Top( Object n, Object 0} int ce Top( Object 0) , We dont specify fields in interfaces, Anel in any case, we don't want anvbondy ee to seep. Here ate PieVisitor? and Pie? interface PieVistor! { Object forBot) Object forTop( Object tPie® r): } abstract class Pie” { ‘abstract ‘Object acvept(PieVisitor? ash); , Define Bot andl Top. 162 © To it ising 9? * Whatever "They ase very familiar class Bot extends Pie” { Object acrept(PieVistor? ast) { return ask forBot(): } ) ‘lass Top extends Pie { Object ¢: Pie® Top(Object Pie” -r) ( tet rao} Object arcept(PieVistor? ask) { return ask forTop\ ar): ) ) Chapter 10 Here is Occurs”. It counts how often some” And this little visitor substitutes one good topping occurs om 1 pie topping for another. class Occurs” implements PieVisito’ (|_| class Subst’ implements PieVisitor” { Oo Oo n | Oct (Objet a) { | | Shee | | = } | | Subst” (Object .n,Object 0) { | pave ova jorbo ( im | Papa jjteee | public Object forTop{Object Pie? r) { public Object forBot() { ble Objet earn new Bot) ‘rn publ Objet for Top Obes te») (1 tw Itge( (tae) ioepuntt} | (ree ptthis)) return nate) “hw Tn) anni) + ue se rou eturn rcpt): ww Top(t(PiP yep this) | ) Great! Now we have almost all the visitors" We remember that one. too. sine Rem”, which ren implements PieVistor” { [class Rem” Object: Rem” (Object 0) { o= 0) publie Object forBot() { return new Bot) } } public Objet forTop(Object Pe? »)( it (omit) return rari) else return ‘new Top(4(Pie™ arp this): } The State of Things to Come 163 new Pieman™().oceTop(mew Anchowy())? Which pie? [And howe many anchovies are on that ple? And what isthe value of yew Pieman'().adi'Top(new Anchovy(})? ‘Thue. If we wish to determine the value of new Pieman().addTop(new Anchovy()). understand what yew Top(new Anchovy().p) return ccrTop(new Anchovy()) "We fist create @ Pieman and then sk how ‘many anchovies accut on the pi. ‘The pie named p in the new Pieman* * None ‘That's right. But that's what happens when "* ‘your have one too many double espressos. Here it means that p changes and that fu references to p reflect the change Whew dows the future begin? That's precisely what a stand-alone semicolon means. Now do we know what return oceTop(new Anchovy()} produces? 164 That's where those stand-alone semicolons ‘come in again. They were never explained Yes, we must understand that. There is no umber + in the world for whieh perth, 0 why should we expect there to be a Java p ssuch that p ew Top(new Anchovy().p)” So what does it mean? ‘And the change is that p has a new topping right? Does it hegin below the stand-alone semicolon? It produces the number of anchovies on p. Chapter 10 ‘And how many are there? And now what isthe value of yew Pieman().addTop(new Anchowy())? No, its not. Take a close Jook. We created a ” new pieman, and that pieman added only ‘one anchor to his p. ‘Yes, there i, Take Took at this Piemant y = new Pieman™() ‘What isthe value of y.addTop{new Anchovy())? And now what is the value of y.sulstTop(new Tuna(),new Anchovy())? Correct. So what is the value of yoceToplnew Anchovy())? Very good. And now take s lok at this Pieman® yy = new Pieman™() What i the value of add Top( new Anchovy()) madd Top{new Anchovy()) ywaddTop(new Salmon()) ‘The State of Things to Come We added one, so the value is L Ws 2, isn't it? Oh, isn't there a way to place several requests with the same pieman? Olay, y stands for some pieman, 1, We know that Stil 1. According to the rules of semicolon ‘and =, this replaces all anchovies on p with ‘unas, changes p. and then counts how many tunas aze on p. 0, because 9 p anchovies. ger contains any What ate the doing at the end? 165, Because this is only half of what we want to Took at. Here isthe other bale ‘yuaddTop(new Tuna) ‘yyaddTop(new Tuna()) ‘nssubstTopltew Tuna().new Anchowy))? Aud what is the value of y.rem Top(new Tuna()) ‘after we are through with all that?” Does that mean remTop always produces 0? Now what is the value of y-oceTop(new Salmon())? ‘And how about y.oceTop(new Salmen())? Is yy the same pieman as before? So is it the same one? When we asked yy to substitute all anchovies by tunas, did the pie change?” Does that mean that anybody can write yup = new Bot() ‘and thus change a pieman like yy? 166 4, First we add two anchovies, then salmon, and two (unas. Then we substitute the two anchovies by two tunas, So y's pie contains four tunas Ws 0, because rem Top first removes all unas ‘and then counts how many there ae lft ‘Yes, it always does 0, because y and yy are two different piemen No, it changed When we eat a pizza pie, we change, but we are still the same. ‘The p in yy changed, nothing else No, because yp's type is Pieman?, p isn’t available. Only addTop, remTop. subst Top and occTop are visible. Chapter 10 Isn't it good that we didn't include pin” Piemant? Clear like soup? “ Can we define a different version of Subst” so ™ ‘that it changes toppings the way’ a pieman changes his pes? ‘And that's what we discuss next. Do you reed a break’? ‘Compare this new PieVisitor with the fest“ one in this chapter | interface PieVistor™ { | Object frBot(Bet that) | Object JorTon(Top tha) ‘True. Here is the unchanged datatype. abstract class Pie® { abstract Object eccept(PieVisitor! ask) ve Define the Bot variant Is it? Why does it use this? . The State of Things to Come ‘Yes, with this trick we can prevent others from changing p (or parts of p) in strange ways. Everything is clear now. ‘Tas like chicken soup, " We can't do that yet No, a cup of coffee will do Tt isn't all that different. PieVistor? must, still provide two methods: forBot and forTop, except that the former now ‘consumes a Bot and the latter Top. ‘The definition is straightforward class Bot extends Pie® { Object accept(PieVisitr® ask) { return ask forBot( this): } } We only have one instance of Bot when we use forBot, namely this, so forBot is clearly supposed to consume 167 ‘That's progress. And that's what happens in Top, 100, class Top extends Pie? { Object f Pre? Top(Object Pie” -r) { ti on} Object accept(PieVisitor™ ask) ( return ask forTop( | Edessa anaes Modify this version of Occurs” so that it Implements the new PieVistor! class Occurs” implements PieVisitor™ { | Object Occurs¥ (Object <0) { a= a} ~ public Object forBot() { ‘return new Integer(0); } public Object forTop(Object #,Pie” r) { if tego) return new Ince (integer) | (r-accept(this))) | neve) i 0 | else | | Feturn vacept(ehis); } | , How does forBot change? 168 “Interesting © ‘The forBot method basically stays the same, but forTop changes somewhat las Oca implements Pier (_] Object es bit -a){ public Object forBot(Bot that) { return new integer(0); } [| public Object forTop(Top that) { If (that tequols(a)) return new Integer (Integer) (thatr.accept(this))) sntValue() +05 | else return thaccept(this); } | Boo “It now consumes « Bot, which is why’ we had to add (Bot that) behind its name. Chapter 10 How does forTop change’? And? Isn't that easy? ‘Then try Rem’. Do we need to do Subst”? And indeed, it is. Happy now? Oh, Points? They will show up later. ‘The State of Things to Come © Ie no longer receives the field values of the corresponding Top. Instead it consumes the entire objeet, which makes the two fields fvailable that and that r “With that, we can teplace the Rilds fan + with that. and that, ‘This modification of Occurs” certainly i Tes easy; we use the same trick, ‘lass Rem” implements PieVisitor! ( Object: Rem’ (Object -0) { ona} public Object forBor(Bot that) { return new Bot() } public Object forTup(Top that) { If (o.oqual(thet.t)) return thot.r.accept( this) else return new Top that. (Pie? that. aceept(this)}; } "Not really: It should be just like Rem” So far, so good. But whats the point of this © Serious 169 Here is the point, What is new about this version of Subst”? Object 0 Subst” (Object -n, Object 0) { public Object forBot(Bot that) { return that: } ublie Object forTop(Top that) { it (o-puals( thoes) { | ‘rant ‘that-raccept( this) return that: } else { that. r-accept(this) return that: ) ‘There are no news Don't they say “no mews i good news?” ‘Yes, because we want to define a version of |" Subst” that modifies toppings without constructing a new pie. What do the methods of Subst” always return’ So how do they substitute toppings? ” 170 Does this saying apply here, 100? ‘That ‘a way of putting it They always return thet, whichis the object that they consume By changing the that before they return Specifically, they change the ¢ field of that to ‘when it equals 0. Chapter 10 What? Correct. And from here on, thet holds the new topping. What is that. accept( this) about? Is there anything else to say about the new Subst”? Do we have to change Pleman? Is it truly safe to modify the toppings of a pie? Can we do LedSubst” now without cresting new instances of LtdSubst” or Top? ‘The that dos it. In the previous Subs, r.accept(this) created a mew pie fom 7 with all toppings appropriately substituted. In our new version, thatraceept(this) modifies the pier ‘contains the appropriate toppings. Not really: It does what it does, which is ‘what we wanted." No, we didn’t change what the visitors do, wwe only changed how they do things. ‘Yes, because the Pieman™ manages the toppings of p. and nobody else sees p. Now that's a piece of pie, ‘The Tenth Bit of Advice When modifications to objects are needed, use a class to insulate the ‘operations that modify objects Otherwise, beware the consequences of your actions ‘The State of Things to Come m Here is a true dessert, It will help us understand what the point of state is. abstract class Point? { nt =, int yi, Point? (int int -) { ) “The datatype has three extensions. class CartesianPt extends Point? { CartesianPt(int int -y) { super(.7, int dstanceT0O0 ( eum ives + Fi} boolean closerToO(Point® p) { return, distanceToO() < padistance 00); } Point® minus(Point® p) { return new CaresianPt(x ~ pry —p.v)s } abstract int distanceT00() y Aren't we missing a variant? im ‘clas ManhattanPt extendls Poin ( | ManhattanPt(int _2,imt _y) { super(-9):} | inv dwncetooO return x+y; } | ———EEE [class ShadowedManhattanPt ‘extends ManhattanPt { int A. int 455 ShadowedManhattanPt(int 7 int -y, int -A,, int Ay) ( super(-2.-0) 4, ‘distanceToO() { return, ‘super.distanceToO()+A, + Ay: } ) essnsdas seeeteaNNanadstaTaTateeetazEa| Yes, we are missing ShadowedCartesianPt Chapter 10 Good enough. We won't need it, Here is one point: new ManhattanPt(l,4) If this point represents a child walking down the streets of Manhattan, how do we represent his movement? ‘Yes. Add to Point? the method moveBy, which consumes two ints and ehanges the fields of « point appropriately ‘The method should return the new distance to the origin. Let ptChild stand for new ManhattanPt(1.4) What is the value of pIChild distance ToO()? The State of Things to Come "Shouldn't we add a method that changes all the feds of the points? First we must know what the method is supposed to produce. Now we know how to do this, abstract class Point? ( int 2 int vy: Point?(int z,int .») { ootean closerToO(Point p) { return distonceT0O() < pdistanceToO() } Point? minss(Poit™ 2) { return snow CartsianPx Int moveBylint 3, pert ae Pry py) } int 45) { ¥ +4, return distanceT0O();} abstract int distance ToO(); } 13 What is the value of otChild. moveiy(2.8)? Good. Now let's watch a child with a hhlinnnfiled balloon that casts « shadow Let ptChildBalloon be new ShadowedManhattanPt(1.4..1) What is the value of pICHildBalloon distance ToOK) What is the value of ptChildBattoon.moveBy(2.8)? Did the balloon move, too? 0 Isn't that powerful? ‘The more things change, the cheaper our Hlesserts get Correct bt ow we ate through and i is time to go out and to celebrate with a grand dinner amt 15. 7, of course. ‘Yes it just moved along as we moved the point Ik sure is. Wo added one method, used it and everything moved ‘Yes, but to get t0 the dessert, we had to work quite hard, Don't forget to leave a tip. Chapter 10 ‘You have reached the end of your introduction to computation with classes, interfaces, and ‘objects. Ate you now ready to tackle a major programming problem? Programming requires two kinds of knowledge: understanding the nature of computation, and discovering the lexicon, features, and idiosyncrasies of a particular programming language. ‘The frst of these is the more dificult intellectual task. If you understand the material in this book, you have mastered that challenge. Still, t would be well worth your time to develop a fuller understanding of all the ‘capabilities in Java—this requires getting access to a running Java system and mastering those Idiosyncrasies. If you want to understand Java and object-oriented systems in greater depth, take a look atthe following books: References 1. Arnold and Gosling, The Jana Programming Language, Addison-Wesley, Reading, Mas- sehsetts, 1906, 2. Buschmann, Meunier, Rohnert, Sommerlad, and Stal A System of Patterns: Pattern Ontented Software Architecture. John Wiley & Sons, Ltd. Chichester, Europe, 1906, 3. Firesmith and Eykholt, Dictionary of Object Technology, SIGS Books, Inc., New York, New York, 1995 and Prentice Hall, Englewood ifs, New Jersey, 1995. 4. Gamma, Helm, Johnson, and Vlissides. Design Patterns. Addison-Wesley, Reading, Massachusetts, 1994 Gosling, Joy, and Steele, The Java Language Specifiation. Addison-Wesley, Reading, Massachusetts, 1996 6. Proe. Design Patterns for Object-Oriented Software Development. Addison-Wesley, Read- ing, Massachusetts, 1994 (Commencement 7 This is for the loyal Schemers and MLers. No, we would forget factor [interface (0 oo! apply(T? x); } splements 00-00" { Public 0-0" apply(o—o! fact) { return new Fact{fact): ) pb lass Fact implements oo! { Object apply( Object); } | one? fact Fact(o-of fact) { foct = facts} [interface 0-00" ( public Object apply(Object i) { om oF appiy(o—o" 2} | "ine ini = (tnteger))-nt Vatu) } if (inti == 0) return new Integer); | interface 20-00-00" ( ) | interface oo! { | : = = J ‘0-+07 apply(oo—oo! 2); a tage z a | inti class Y implements 00-00-00" ( (Integer) Fas ents See ew tec ~1)) return new H(f).apply(new H(f)); } ant Value()}; non [ieee all [tase # implements T | 2000! J | Hose 1 | =f) | pu ot apt) ( Need return fapplynew (2): } | | class G implements oo" ( Ts | erat | public Object appy( Object y) { return (zappy(2)).apply(y): } } l Copyrighted materi Index Ads, 128 salty, 188 ‘rchowr 9,5, 6h 5, 68 72 ‘pte, ot ase, 10 brsFeie” 104 isnt 2 bist, 102,109 Bek 9.7, 8, 8S, 86, 1, 9,162, 167 Bd, 00, 01, 10,10, 122 bree, 101 CrtesinPs, 513,37, 98-40, 199,172 (Chere 4,5 61, 65 Const, 118 Copper, 2 Grom 29,66, 55 Digge, 2 agen i n9 ‘dulce TiO, Uf, 8,10, 14, 2,172 Empty, 124 eu, 72,7, 100 Ber, 119 EpVister, 118 Fic, 100 Fah, 69,72 ais, 29 Habe’, 147,155, iWeige, 108 seu ant Isp 113 ssligetirian, 25,27 levageiin 6 ‘Vane, 3, 31,36, MeeViitr’, 7 Kebab, 25,36 Laye?, 10 * aan, 100 Urata 96, 07,199 906 MarhananP, 5, 13,98, 99,199,172 ‘mas, 130 mote, 1 elles, 15, 15T Rime 7. cop, 161 (ecu, 24, 165,168 OneMereThan. 7,19 ‘Onon, 1,27 25, 36, 50,2 fonOnin 1 27 OnyOsone 37.0 Penta Pepper 4.37 Pie TR 8,25, 8, 102, 107 Bevin? 2 162 1 Planar, 162 Peamae’4 6h ae?) 20 pier, 20 Pont? 5,13, 40, 199,172,178, prod, i2t Pred ‘119 Radish, 28.36 ema 5, 9, 0) Rena, oe 7h 73 Rents, 74 Rem, 77,7, 98, 163, 160 emin, 7 ae Sate, 90 Som 5 Salmon, 6.72 Sant Sausage. 8,58, 63-65, Sexong®, 4 ser. a SetBa, 16,1 ShafowedCaresanPt, 14, M2 ‘Shadomeadtanatanee, 138,172 Shane! 165 ShapeVitor 148 Shah, 10,27, 59,08 Shien, 28,30 Sie 29 Shaw 16, 27,59, 02 Stee, 0 Spiaeh, 5 Spy 10D, 01, 108,10, 122 Shui, tis Ides shite, 52.58 SubARC?, 66 Suba®, iat 1 Subs a Subs, 85,87, 80,4, 152496, 16,179 Subse | abatToy 11 Swed, 29 Tomato, 16.27.28, 30,59, 2 op, 8, 78.85, 85,86, 91,93, 162168 TooAwe?. 66 Tram th ee, 100, 201, 107,109, 22 Tenater? 112 ‘Subs, Ut Meise! 109 nin, 149, 150 UnioViter, 150 Wood, 20” occ, 1 Copyrighted material Copyrighted material A Little Java, A Few Patterns, ‘Matthias Felleisen and Daniel PTviedman Foreword by Raiph .Johnon Drawings by Duane Bibby 0 snterne na very short tine ithas become one of the moet

Vous aimerez peut-être aussi