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