Abstracting over the behavior Code for this part of the lecture can be found here. In the previous lecture we have seen that the common functional interface for several classes allows us to abstract not only over the definition of two lists, but also over their comparison, and even over a common mehtod. Consider the following class diagram: +---------------------------+ | AList | +---------------------------+ | boolean same(Obj that) | | boolean contains(Obj that)| +---------------------------+ | / \ --- | --------------------------- | | +-------------+ +---------------+ | MTList | | ConsList | +-------------+ +---------------+ +-------------+ +----| ISame fist | | | AList rest | | +---------------+ v +-------------------------+ | ISame | +-------------------------+ | boolean same(ISame that)| +-------------------------+ | / \ --- | -------------------- | | +--------------+ +--------------+ | Book | | Song | +--------------+ +--------------+ | String title | | String title | | String author| | int time | | int year | +--------------+ +--------------+ We would like to design a method that returns true if this AList contains a Book written before 1950. Otherwise it returns false. In class MTList we add the following piece of code: //is there a book in this list written before 1950 boolean hasOldBook(){ return false; } In class ConsList we add the following piece of code: //is there a book in this list written before 1950 boolean hasOldBook(){ if ((Book)this.first.year<1950) return true; else return this.rest.hasOldBook() } Note:if the first element of this AList is not a Book, JAVA will raise an exception We would like also to design a method that returns true if this AList contains a Book written by GBS. Otherwise it returns false. In class MTList we add the following piece of code: //is there a book in this list written by GBS boolean hasGBSBook(){ return false; } In class ConsList we add the following piece of code: //is there a book in this list written by GBS boolean hasGBSBook(){ if ((Book)this.first.author.equals("GBS")) return true; else return this.rest.hasGBSBook() } It is obvious that there are many structural similarities between the two methods. So we can abstract over those similarities and a design a method that checks if this AList contains an element that satisfies a given predicate. In order to do that we need to extend our class diagram: +---------------------------+ | ISelect | +---------------------------+ | boolean select(Object obj)| +---------------------------+ | / \ --- | ---------------------------- | | | +----------+ +---------+ +---------+ | LongSong | | GBSBook | | OldBook | +----------+ +---------+ +---------+ +----------+ +---------+ |int year | +---------+ Now, we can designour genral method that returns true if this AList contains an element that satisfies the given predicate. Otherwise it returns false. In class MTList we add the following piece of code: //is there an element in this list that satisfies pred boolean anysuch(ISelect pred){ return false; } In class ConsList we add the following piece of code: //is there an element in this list that satisfies pred boolean anysuch(ISelect pred){ if (pred.select(this.first)) return true; else return this.rest.anysuch(pred) } We also need to design our predicates. In class LongSong we add the following piece of code: //does the given song last more than 30 sec boolean select(Object obj){ return (((Song)obj).time>30); } In class GBSBook we add the following piece of code: //is the given book written by GBS boolean select(Object obj){ return (((Book)obj).author.equals("GBS")); } In class OldBook we add the following piece of code: //is the given book written befor this year boolean select(Object obj){ return (this.year>((Book)obj).year); } We can now write examples of the form: songlist.anysuch(new LongSong()); booklist.anysuch(new GBSBook()); booklist.anysuch(new OldBook(1920));