/* --- CSU213 Spring 2005 Lecture Notes --------- Copyright 2005 Viera K. Proulx Lecture 16: A Road Trip */ /* Goals: - learn to use classes that represent functional behavior Introduction: We came back from a long car trip. We recorded the miles traveled each time we refueled, together with the price of gas and the number of gallons of gas we bought. We would like to look back an analyze our expenses, gas mileage, distances. We first design the class to represent the information about each segment of the trip, and a list of segments to represent the whole trip information. The class diagrams are shown here, the code is at the end: +------+ | ALoS |<--------------+ +------+ | +------+ | / \ | --- | | | ------------------ | | | | +-------+ +---------------+ | | MTLoS | | ConsLoS | | +-------+ +---------------+ | +-------+ +-| Segment first | | | | ALoS rest |----+ | +---------------+ | v +-------------+ | Segment | +-------------+ | String from | | String to | | int miles | | int gallons | | int price | +-------------+ We want to produce a list of cities from which we started each segment of the trip, a list of information about the miles per gallon consumption for each segment, and the list of the costs of the trip segments. We plan to record this infromation as instances of the classes String, MPG, and Cost. The later two are defined as follows: +-------------+ +-------------+ | MPG | | Cost | +-------------+ +-------------+ | String from | | String from | | String to | | String to | | int mpg | | int cost | +-------------+ +-------------+ We make examples of segments, trips, and the desired results: Segment b2nyc = new Segment("Boston", "NYC", 200, 10, 210); Segment nyc2ph = new Segment("NYC", "Philly", 180, 9, 220); Segment ph2dc = new Segment("Philly", "DC", 120, 12, 200); Segment dc2nor = new Segment("DC", "Norfolk", 150, 10, 200); ALoObj mtlist = new MTLoObj(); ALoObj mytrip = new ConsLoObj(b2nyc, new ConsLoObj(nyc2ph, new ConsLoObj(ph2dc, new ConsLoObj(dc2nor, mtlist)))); MPG b2nycmpg = new MPG("Boston", "NYC", 200/10); MPG nyc2phmpg = new MPG("NYC", "Philly", 180/9); MPG ph2dcmpg = new MPG("Philly", "DC", 120/12); MPG dc2normpg = new MPG("DC", "Norfolk", 150/10); Cost b2nycCost = new Cost("Boston", "NYC", 10 * 210); Cost nyc2phCost = new Cost("NYC", "Philly", 9 * 220); Cost ph2dcCost = new Cost("Philly", "DC", 12 * 200); Cost dc2norCost = new Cost("DC", "Norfolk", 10 * 200); Our plan is to design three methods in the classes that represent a list of segments as follows: makeCities: ALoS -> ALoStrings makeMPGs: ALoS -> ALoMPGs makeCosts: ALoS -> ALoCosts We already know that it is not necessary to design a separate list for each type of objects - we can instead build in each case a list of Object-s. Next, we need to define the methods in the class segment that produce from the given segment the desired new object: a String, an MPG object, or a Cost object: Exercise: Follow the design recipe to design these methods. (The results are included in the code below.) Here we show just the purpose statements and the headers for these methods: // produce the city of origin for this segment of the trip String makeCity(){...} // produce the record of gas mileage for this segment of the trip MPG makeMPG(){...} // produce the record of the cost of this segment of the trip Cost makeCost(){...} as well as some examples: b2nyc.makeCity() --> "Boston" nyc2ph.makeCity() --> "NYC" b2nyc.makeMPG() --> b2nycmpg ph2dc.makeMPG() --> ph2dcmpg b2nyc.makeCost() --> b2nycCost ph2dc.makeCost() --> ph2dcCost We can now design the methods makeCities: ALoS -> ALoStrings makeMPGs: ALoS -> ALoMPGs makeCosts: ALoS -> ALoCosts Each of the methods just consumes this list of segments and produces the appropriate list of objects. Let us start with the methods for class ALoS and MTLoS. In the class ALoS: // produce a list of origins for all segments of this trip abstract ALoObj makeCities(); // produce a list of MPG records for all segments of this trip abstract ALoObj makeMPGs(); // produce a list of cost records for all segments of this trip abstract ALoObj makeCosts(); In the class MTLoS: // produce a list of origins for all segments of this trip ALoObj makeCities(){ return new MTLoObj(); } // produce a list of MPG records for all segments of this trip ALoObj makeMPGs(){ return new MTLoObj(); } // produce a list of cost records for all segments of this trip ALoObj makeCosts(){ return new MTLoObj(); } The template for the ConsLoObj cases is next: ... this.first ... ... this.first.makeCity() ... ... this.first.makeMPG() ... ... this.first.makeCost() ... ... this.rest ... ... this.rest.makeCities() ... ... this.rest.makeMPGs() ... ... this.rest.makeCosts() ... The examples are: boolean testMakeCities1 = mtlist.makeCities().same(mtloobj); boolean testMakeCities2 = mytrip.makeCities().same( new ConsLoObj("Boston", new ConsLoObj("NYC", new ConsLoObj("Philly", new ConsLoObj("DC", mtloobj))))); boolean testMakeMPGs1 = mtlist.makeMPGs().same(mtloobj); boolean testMakeMPGs2 = mytrip.makeMPGs().same( new ConsLoObj(b2nycmpg, new ConsLoObj(nyc2phmpg, new ConsLoObj(ph2dcmpg, new ConsLoObj(dc2normpg, mtloobj))))); boolean testMakeCosts1 = mtlist.makeCosts().same(mtloobj); boolean testMakeCosts2 = mytrip.makeCosts().same( new ConsLoObj(b2nycCost, new ConsLoObj(nyc2phCost, new ConsLoObj(ph2dcCost, new ConsLoObj(dc2norCost, mtloobj))))); However, we cannot run the first set of tests, because the 'same' method for the classes that represent a list of Object-s expects the list elements to implement the ISame interface. We are not allowed to extend the Java String class. We will omit those tests for now. The methods for the class ConsLoS follow easily: // produce a list of origins for all segments of this trip ALoObj makeCities(){ return new ConsLoObj(this.first.makeCity(), this.rest.makeCities()); } // produce a list of MPG records for all segments of this trip ALoObj makeMPGs(){ return new ConsLoObj(this.first.makeMPG(), this.rest.makeMPGs()); } // produce a list of cost records for all segments of this trip ALoObj makeCosts(){ return new ConsLoObj(this.first.makeCost(), this.rest.makeCosts()); } Again, we see that the methods makeCities, makeMPGs and MakeCosts differ only in the way in which the list element 'first' is used to produce the element of the new list. Furthermore, recalling the lecture in which we built the 'ormap', we see that this, too, is one of our familiar Scheme loops - the map. Let us recall the purpose, contract and header for 'map': ;; map: (X -> Y) (listof X) -> (Listof Y) ;; to construct a list by applying f to each item on alox ;; that is, (map f (list x-1 ... x-n)) = (list (f x-1) ... (f x-n)) (define (map f alox) ... ) Our methods makeCity, makeMPG, and makeCost in the class Segment played the role of function f above. We want to abstract over them to define just one method makeTripRecord. But, again, we can only pass an instance of a class as an argument to a method. We define an interface: interface IObj2Obj{ // produce an object from the given object Object makeObject(Object obj); } We can now supply an argument of the type IObj2Obj to the method makeTripRecord. The only significant chane will be in the class ConsLoS: // produce a list of records for all segments of this trip ALoObj makeTripRecord(IObj2Obj transform){ return new ConsLoObj(transform.makeObject(this.first), this.rest.makeTripRecord(transform)); } To complete the abstraction, we need to define classes that implement the IObj2Obj interface with the three methods that perform the original transformation from Segment to String, MPG, and Cost objects. (We also add the wrapper class for our resulting String, so we can run our tests --- see the code.) // to produce the from city string (wrapper) from the given segment class MakeCity implements IObj2Obj{ Object makeObject(Object obj){ return new StringWrapper(((Segment)obj).from); } } // to produce the MPG record from the given segment class MakeMPG implements IObj2Obj{ Object makeObject(Object obj){ return new MPG(((Segment)obj).from, ((Segment)obj).to, ((Segment)obj).miles / ((Segment)obj).gallons); } } // to produce the Cost record from the given segment class MakeCost implements IObj2Obj{ Object makeObject(Object obj){ return new Cost(((Segment)obj).from, ((Segment)obj).to, ((Segment)obj).gallons * ((Segment)obj).price); } } Finally, our tests confirm that the original examples work equally well when we use the new abstracted method makeTripRecord. The full tests are shown in the code, here we just show the method invocation for three test cases: mytrip.makeTripRecord(new MakeCity()) mytrip.makeTripRecord(new MakeMPG()) mytrip.makeTripRecord(new MakeCost()) Exercise: Make a concise collection of the Scheme loops 'ormap', 'andmap', 'filter', and 'map' for the class that represent lists of Objec-s, that produce either a boolean value (for 'ormap' and 'andmap') or a list of objects (for 'filter' and 'map'), and use 'generic' interfaces IObj2Bool or IObj2Obj for the function object arguments. Make several examples of use, for different source and target lists. */ /* ; ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ;;; ; ;; ;; ;;; ; ; ;; ; ; ;; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ;;;;; ; ; ; ;;;; ; ; ; */ interface ISame{ // determine whether this object is the same as the given object boolean same(Object obj); } /* ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ;;; ;; ; ; ;; ;; ;;; ; ;; ;;;; ; ;; ; ; ; ;; ;; ;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ; ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ;;; ;;;; ;; ; ; ; ; ;;;; ; ; ;; ; ; ; ; ; ; ;;;; */ // to represent a segment of a road trip class Segment implements ISame{ String from; String to; int miles; int gallons; int price; Segment(String from, String to, int miles, int gallons, int price) { this.from = from; this.to = to; this.miles = miles; this.gallons = gallons; this.price = price; } // determine whether this segment is the same as the given object boolean same(Object obj){ return this.from.equals(((Segment)obj).from) && this.to.equals(((Segment)obj).to) && this.miles == ((Segment)obj).miles && this.gallons == ((Segment)obj).gallons && this.price == ((Segment)obj).price; } // produce the city of origin for this segment of the trip String makeCity(){ return this.from; } // produce the record of gas mileage for this segment of the trip MPG makeMPG(){ return new MPG(this.from, this.to, this.miles/this.gallons); } // produce the record of the cost of this segment of the trip Cost makeCost(){ return new Cost(this.from, this.to, this.gallons * this.price); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.from ... ... this.to ... ... this.miles ... ... this.gallons ... ... this.price ... } */ } /* ; ; ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ;;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ;;; ;;; ; ; ; */ // to represent a list of segments of a road trip abstract class ALoS { // produce a list of origins for all segments of this trip abstract ALoObj makeCities(); // produce a list of MPG records for all segments of this trip abstract ALoObj makeMPGs(); // produce a list of cost records for all segments of this trip abstract ALoObj makeCosts(); // produce a list of records for all segments of this trip abstract ALoObj makeTripRecord(IObj2Obj transform); /* // ** DRAFT TEMPLATE ** Edit as needed. // purpose statement abstract ??? mmm(); */ } /* ; ; ; ; ; ; ;;;;;;; ; ;;;; ; ;; ;; ; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ; ; ; ;;; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ;;; ;;; ; ; ; */ // to represent an empty list of segments of a road trip class MTLoS extends ALoS { MTLoS() { } // produce a list of origins for all segments of this trip ALoObj makeCities(){ return new MTLoObj(); } // produce a list of MPG records for all segments of this trip ALoObj makeMPGs(){ return new MTLoObj(); } // produce a list of cost records for all segments of this trip ALoObj makeCosts(){ return new MTLoObj(); } // produce a list of records for all segments of this trip ALoObj makeTripRecord(IObj2Obj transform){ return new MTLoObj(); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { } */ } /* ; ; ; ; ;;;; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;; ;;; ; ;;; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ;;; ; ; ;;; ;;;;;; ;;; ;;; ; ; ; */ // to represent a nonempty list of segments of a road trip class ConsLoS extends ALoS { Segment first; ALoS rest; ConsLoS(Segment first, ALoS rest) { this.first = first; this.rest = rest; } // produce a list of origins for all segments of this trip ALoObj makeCities(){ return new ConsLoObj(this.first.makeCity(), this.rest.makeCities()); } // produce a list of MPG records for all segments of this trip ALoObj makeMPGs(){ return new ConsLoObj(this.first.makeMPG(), this.rest.makeMPGs()); } // produce a list of cost records for all segments of this trip ALoObj makeCosts(){ return new ConsLoObj(this.first.makeCost(), this.rest.makeCosts()); } // produce a list of records for all segments of this trip ALoObj makeTripRecord(IObj2Obj transform){ return new ConsLoObj(transform.makeObject(this.first), this.rest.makeTripRecord(transform)); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.first ... ... this.rest.mmm() ... } */ } /* ; ; ; ; ; ; ;;;;; ;;;; ; ;; ;; ; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ; */ // to represent the mile per gallons consumption per segment class MPG implements ISame{ String from; String to; int mpg; MPG(String from, String to, int mpg) { this.from = from; this.to = to; this.mpg = mpg; } // determine whether this MPG object is the same as the given object boolean same(Object obj){ return this.from.equals(((MPG)obj).from) && this.to.equals(((MPG)obj).to) && this.mpg == ((MPG)obj).mpg; } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.from ... ... this.to ... ... this.mpg ... } */ } /* ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ;;; ;;; ;;;; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ;;; ;;; ;; ; ; ; */ // to represent the cost of travel for one segment of a road trip class Cost implements ISame{ String from; String to; int cost; Cost(String from, String to, int cost) { this.from = from; this.to = to; this.cost = cost; } // determine whether this MPG object is the same as the given object boolean same(Object obj){ return this.from.equals(((Cost)obj).from) && this.to.equals(((Cost)obj).to) && this.cost == ((Cost)obj).cost; } // produce a list of origins for all segments of this trip ALoObj makeCities(){ return new MTLoObj(); } // produce a list of MPG records for all segments of this trip ALoObj makeMPGs(){ return new MTLoObj(); } // produce a list of cost records for all segments of this trip ALoObj makeCosts(){ return new MTLoObj(); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.from ... ... this.to ... ... this.cost ... } */ } /* ; ; ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;;;;;; ;;; ;;;; ; ;; ; ; ; ; ; ; ;; */ /* +--------+ | ALoObj |<--------------+ +--------+ | +--------+ | / \ | --- | | | ------------------ | | | | +---------+ +--------------+ | | MTLoObj | | ConsLoObj | | +---------+ +--------------+ | +---------+ | Object first | | | ALoObj rest |-+ | +--------------+ | | | | +--+ */ // to represent a list of objects abstract class ALoObj implements ISame{ // determine whether this list of objects is the same as the given object boolean same(Object obj){ return this.sameALoObj((ALoObj) obj); } // is this an empty list of objects abstract boolean isEmpty(); // determine whether this list of objects is the same as // the given list of objects abstract boolean sameALoObj(ALoObj alist); /* // ** DRAFT TEMPLATE ** Edit as needed. // purpose statement abstract ??? mmm(); */ } /* ; ; ; ; ; ; ;;;;;;; ; ;;;; ; ; ; ;; ;; ; ; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ;;;;;; ;;; ;;;; ; ;; ; ; ; ; ; ; ;; */ // to represent an empty list of objects class MTLoObj extends ALoObj { MTLoObj() { } boolean isEmpty(){ return true; } boolean sameALoObj(ALoObj alist){ return alist.isEmpty(); } /* TEMPLATE ** Edit as needed. ??? mmm() { } */ } /* ; ; ; ; ;;;; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;; ;;; ; ;;; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ;;;; ;;; ; ; ;;; ;;;;;; ;;; ;;;; ; ;; ; ; ; ; ; ; ;; */ // to represent a nonempty list of objects class ConsLoObj extends ALoObj { Object first; ALoObj rest; ConsLoObj(Object first, ALoObj rest) { this.first = first; this.rest = rest; } boolean isEmpty(){ return false; } boolean sameALoObj(ALoObj alist){ if (alist.isEmpty()) return false; else return ((ISame)this.first).same(((ConsLoObj)alist).first) && this.rest.sameALoObj(((ConsLoObj)alist).rest); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.first ... ... this.rest.mmm() ... } */ } /* ; ; ; ; ; ;;;; ; ; ;;;; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ; ; ; ;;;; ; ;; ; ;;;;;; ;;;; ; ;; ; ; ; ; ; ; ; ; ;; ;; */ interface IObj2Obj{ // produce an object from the given object Object makeObject(Object obj); } /* ; ; ; ; ; ; ; ;;;; ; ; ;; ;; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ; ;;; ; ; ;;; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ;;; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ;;;; ;;;; ; ;; ; ; ; ; ; ; ; */ // to produce the from city string (wrapper) from the given segment class MakeCity implements IObj2Obj{ Object makeObject(Object obj){ return new StringWrapper(((Segment)obj).from); } } /* ; ; ; ; ; ; ; ; ; ;;;;; ;;;; ; ;; ;; ; ;; ;; ; ; ; ; ; ;; ;; ; ;; ;; ; ; ; ; ; ; ; ; ;;; ; ; ;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ; ; ; ; ;;;; ;;; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ;;;; ; ; ; ;;;;; ; ; ; */ // to produce the MPG record from the given segment class MakeMPG implements IObj2Obj{ Object makeObject(Object obj){ return new MPG(((Segment)obj).from, ((Segment)obj).to, ((Segment)obj).miles / ((Segment)obj).gallons); } } /* ; ; ; ; ; ; ; ;;;; ; ;; ;; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ; ;;; ; ; ;;; ; ;;; ;;; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ;;;; ;;; ;;;;;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;; ; ; ;;;; ;;;; ;;; ;;; ;; ; ; ; */ // to produce the Cost record from the given segment class MakeCost implements IObj2Obj{ Object makeObject(Object obj){ return new Cost(((Segment)obj).from, ((Segment)obj).to, ((Segment)obj).gallons * ((Segment)obj).price); } } /* ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ; ; ; ; ;; ;; ; ; ; ; ; ; ; ;;; ; ;; ; ;; ;;; ; ; ; ;; ; ;; ; ;; ; ; ;; ; ; ; ; ;; ; ; ;; ; ;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;; ; ;; ; ; ; ; ;;; ;; ; ; ; ; ;; ; ; ; ; ;;;;; ; ;; ; ;; ;;;; ; ; ; ; ; ; ; ; ; ; ; ;;;; ; ; */ // to allow String object comparison with 'same' method class StringWrapper implements ISame{ String s; StringWrapper(String s){ this.s = s; } boolean same(Object obj){ return s.equals(((StringWrapper)obj).s); } } /* ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;; ;; ; ;; ; ;;; ;;; ; ;;;;; ; ; ; ; ;; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ;;;; ; ; ; ; ; ; ;;;;;; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;;;;;;; ; ;;;;; ; ; ; ; ;; ; ;;;; ;;; ; ; ; ; ; ; */ class Examples{ Examples() {} Segment b2nyc = new Segment("Boston", "NYC", 200, 10, 210); Segment nyc2ph = new Segment("NYC", "Philly", 180, 9, 220); Segment ph2dc = new Segment("Philly", "DC", 120, 12, 200); Segment dc2nor = new Segment("DC", "Norfolk", 150, 10, 200); ALoS mtlist = new MTLoS(); ALoS mytrip = new ConsLoS(b2nyc, new ConsLoS(nyc2ph, new ConsLoS(ph2dc, new ConsLoS(dc2nor, mtlist)))); // testing the method same in the class segment boolean testSameSegment1 = b2nyc.same(ph2dc) == false; boolean testSameSegment2 = ph2dc.same( new Segment("Philly", "DC", 120, 12, 200)) == true; MPG b2nycmpg = new MPG("Boston", "NYC", 200/10); MPG nyc2phmpg = new MPG("NYC", "Philly", 180/9); MPG ph2dcmpg = new MPG("Philly", "DC", 120/12); MPG dc2normpg = new MPG("DC", "Norfolk", 150/10); Cost b2nycCost = new Cost("Boston", "NYC", 10 * 210); Cost nyc2phCost = new Cost("NYC", "Philly", 9 * 220); Cost ph2dcCost = new Cost("Philly", "DC", 12 * 200); Cost dc2norCost = new Cost("DC", "Norfolk", 10 * 200); boolean testMakeCity1 = b2nyc.makeCity().equals("Boston"); boolean testMakeCity2 = nyc2ph.makeCity().equals("NYC"); boolean testMakeMPG1 = b2nyc.makeMPG().same(b2nycmpg); boolean testMakeMPG2 = ph2dc.makeMPG().same(ph2dcmpg); boolean testMakeCost1 = b2nyc.makeCost().same(b2nycCost); boolean testMakeCost2 = ph2dc.makeCost().same(ph2dcCost); ALoObj mtloobj = new MTLoObj(); /* the following tests cannot be easily performed, because we cannot compare two String-s using the 'same' method that works for all classes we defined. We could instead define a class StringWrapper that contains one String field and implements ISame and use that as the target class for the makeCity method in the class Segment. boolean testMakeCities1 = mtlist.makeCities().same(mtloobj); boolean testMakeCities2 = mytrip.makeCities().same( new ConsLoObj("Boston", new ConsLoObj("NYC", new ConsLoObj("Philly", new ConsLoObj("DC", mtloobj))))); */ boolean testMakeMPGs1 = mtlist.makeMPGs().same(mtloobj); boolean testMakeMPGs2 = mytrip.makeMPGs().same( new ConsLoObj(b2nycmpg, new ConsLoObj(nyc2phmpg, new ConsLoObj(ph2dcmpg, new ConsLoObj(dc2normpg, mtloobj))))); boolean testMakeCosts1 = mtlist.makeCosts().same(mtloobj); boolean testMakeCosts2 = mytrip.makeCosts().same( new ConsLoObj(b2nycCost, new ConsLoObj(nyc2phCost, new ConsLoObj(ph2dcCost, new ConsLoObj(dc2norCost, mtloobj))))); // test the final abstraction through the method makeTripRecord boolean testMakeRecordCities1 = mtlist.makeTripRecord(new MakeCity()).same(mtloobj); boolean testMakeRecordCities2 = mytrip.makeTripRecord(new MakeCity()).same( new ConsLoObj(new StringWrapper("Boston"), new ConsLoObj(new StringWrapper("NYC"), new ConsLoObj(new StringWrapper("Philly"), new ConsLoObj(new StringWrapper("DC"), mtloobj))))); boolean testMakeRecordMPGs1 = mtlist.makeTripRecord(new MakeMPG()).same(mtloobj); boolean testMakeRecordMPGs2 = mytrip.makeTripRecord(new MakeMPG()).same( new ConsLoObj(b2nycmpg, new ConsLoObj(nyc2phmpg, new ConsLoObj(ph2dcmpg, new ConsLoObj(dc2normpg, mtloobj))))); boolean testMakeRecordCosts1 = mtlist.makeTripRecord(new MakeCost()).same(mtloobj); boolean testMakeRecordCosts2 = mytrip.makeTripRecord(new MakeCost()).same( new ConsLoObj(b2nycCost, new ConsLoObj(nyc2phCost, new ConsLoObj(ph2dcCost, new ConsLoObj(dc2norCost, mtloobj))))); }