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);
      }
   }