Csu213, Wednesday 1/24/07 Previously, no real new stuff, only 'dynamic dispatch' where java implements the 'cond' for us, we just have to put the cases in the right classes We've seen lists in Scheme. Now lets do an example, all in Java, for an iTunes-like application Start with a datatype to represent a single Song. Then we build a simple list of songs. Here's the class diagram: +----------------+ +---->| Song | | +----------------+ | | String title | | | String artist | | | int size | | | double price | | +----------------+ | | +--------+ | | LoS |<-------------------+ | +--------+ | | | | | / \ | | +---+ | | | | | +------+---------------+ | | | | | | +-----+-----+ | | | | MtLoS | +--------+-----+ | | +-----------+ | ConsLoS | | | +--------------+ | +------------------------| Song first | | | Los rest |--+ +--------------+ // * Examples * Song help = new Song("Help", "Beatles", 50, 0.99); Song dsotm = new Song("Dsotm", "Pink Floyd", 100, 0.25); Song hts = new Song("Hts", "Muse", 10, 0.90); LoS mtlos = new MtLoS(); LoS list1 = new ConsLoS(this.help, this.mtlos); LoS list2 = new ConsLoS(this.dsotm, new ConsLoS( this.hts, this.list1)); What types of things might one want to do/ask with an LoS? - How many songs are there? (ie. count them) - Find the total size? - Is there a song by artist X in the list? - Give me a list of all the songs by artist X in this list. (filter) One at a time... ****************************************** How Many... * Problem analysis/data definition; Above * Purpose/Contract Purpose : to count the songs in *this* ListOfSongs Contract: int count(); // * Examples this.mtlos.count() --> 0 this.list1.count() --> 1 this.list2.count() --> 3 * Template: we update the ConsLoS constructor to include the 'running' template allong with our new method, 'count' // ... this.first ... --- Song // ... this.first.title ... --- String // ... this.first.artist ... --- String // ... this.first.size ... --- int // ... this.first.price ... --- double // ... this.rest ... --- LoS // ... this.rest.count() ... --- int * Implementation... we update each of the definitions to include the new method... In interface LoS... // Count the number of songs in *this* LoS int count(); In class MtLoS... // Count the number of songs in *this* empty LoS int count(){ return 0; } In class ConsLoS... // Count the number of songs in *this* non-empty LoS int count(){ return 1 + this.rest.count(); } ****************************************** Total Size... * Purpose/Contract Purpose : to find the total size of all the songs in *this* List of Songs Contract: int totalSize(); // * Examples this.mtlos.totalSize() --> 0 this.list1.totalSize() --> 50 this.list2.totalSize() --> 160 * Template: we update the ConsLoS constructor to include our new method, 'totalSize' // ... this.rest.totalSize() ... --- int * Implementation... we update each of the definitions to include the new method... In interface LoS... // Find the total size of all the songs in *this* LoS int totalSize(); In class MtLoS... // Find the total size of all the songs in *this* empty LoS int totalSize(){ return 0; } In class ConsLoS... // Find the total size of all the songs in *this* non-empty LoS int totalSize(){ return this.first.size + this.rest.totalSize(); } ****************************************** Note that we have to use our knowledge of the inner details of a Song. Using (or not using) direct access to dats-members is mostly a judgment call. In this case ConsLoS and Song are reasonably good 'friends' but this is mainly to save board space. Normally we would create functions to access the members of Song. For instance... imagine that instead of storing the 'size' directly, it made sense to store the length (in seconds) and the encoding type. We would then give a method to find the size of the Song using this information instead of allowing direct access. If we used a method instead of the field directly both implementations would work with our ConsLoS without changing any of the ConsLoS code. ****************************************** Countains... * Purpose/Contract Purpose : Tell if there is a song by the given artist in *this* List of Songs Contract: boolean contains(String artist); // * Examples this.mtlos.contains("Beatles") --> false this.list1.contains("Beatles") --> true this.list1.contains("Hts") --> false this.list2.contains("Hts") --> true this.list2.contains("ABC") --> false * Template: we update the ConsLoS constructor to include our new method, 'contains' // ... this.rest.contains(String artist) ... --- boolean * Implementation... we update each of the definitions to include the new method... In interface LoS... // Tell if there is a song by the given artist in *this* LoS boolean contains(String artist); In class MtLoS... // Tell if there is a song by the given artist in *this* empty LoS boolean contains(String artist){ return false; } In class ConsLoS... // Tell if there is a song by the given artist in *this* non-empty LoS boolean contains(String artist){ return this.first.artist.equals(artist) || this.rest.contains(artist); } ****************************************** All Songs By Artist... * Purpose/Contract Purpose : Create a list of all songs by the given artist in *this* List of Songs Contract: LoS allBy(String artist); // * Examples this.mtlos.allBy("Pink Floyd") --> this.mtlos this.list1.allBy("Pink Floyd") --> this.mtlos this.list1.allBy("Beatles") --> this.list1 this.list2.allBy("Pink Floyd") --> new ConsLoS(this.dsotm, mtlos) this.list2.allBy("Beatles") --> this.list1 * Template: we update the ConsLoS constructor to include our new method, 'totalSize' // ... this.rest.contains(String artist) ... --- LoS * Implementation... we update each of the definitions to include the new method... In interface LoS... // Create a list of all songs by the given artist in *this* LoS LoS allBy(String artist); In class MtLoS... // Create a list of all songs by the given artist in *this* empty LoS LoS allBy(String artist){ return this; } In class ConsLoS... // Create a list of all songs by the given artist in *this* non-empty LoS LoS allBy(String artist){ if(this.first.equals(artist)){ return new ConsLoS(this.first, this.rest.allBy(artist)); } else { return this.rest.allBy(artist); } }