// TSRJ Workshop 2008 - Advanced Track // Lecture - Wednesday pm - Part 1: Lifting fields to super classes // CS U213 Spring 2007 // Lecture 12: February 5, 2007 /* Goals: - Abstraction : Learning to design abstract classes and methods Introduction: Looking at the following data definition (represented as a class diagram) it is clear that there is a great deal of -- we hope unnecessary -- repetition. The design recipe for abstractions tells us to identify the commonalities and abstract over them. This may look like extra work, but sometimes it is actually necessary. +---------+ | LibItem |<----------------------------+ +---------+ | / \ | | | - - - - - - - - - - - - - - - - - - - - - - | | | | | +---------------+ +---------------+ +--------------+ | | Book | | CD | | Magazine | | +---------------+ +---------------+ +--------------+ | | int catNo | | int catNo | | int catNo | | | String title | | String title | | String title | | | int dueDate | | int dueDate | | int dueDate | | | String author | | String artist | | int vol | | +---------------+ +---------------+ | int no | | +--------------+ | | | +----------+ | | ListOfLI |<---------------+ | +----------+ | | +----------+ | | | | | / \ | | --- | | | | | --------------------- | | | | | | +------------+ +---------------+ | | | MTListOfLI | | ConsListOfLI | | | +------------+ +---------------+ | | +------------+ | LibItem first |----+-----------------------+ | ListOfLI rest |-+ | +---------------+ | | | | +--+ Consider the following problem. You are trying to find out if our list contains a given item. In order to do that, you need to be able to compare two library items and determine whether the catalog number of one of then is than the catalog number of the other one. This calls for the following purpose statement and method headers: IN ListOfLI: //does this list contain the given item? boolean contains(LibItem that); IN LibItem: //is this libItem same as the given item? boolean same(LibItem that); However, we have no instances of LibItems. So, we add the method to every class that implements LIbItem interface. In the class Book we look at the template: ... this.catNo ... -- int ... this.title ... -- String ... this.dueDate ... -- int ... this.author ... -- String and, of course, we have ... that ..., but the only thing we know about it is that it is a LibItem. We would like our method to handle the following cases: LibItem b1=new Book(77,"HtDP",2001,"MF") LibItem b2=new Book(33,"LPP",1944,"STX") LibItem c1=new CD(68,"Live",1992,"AC-DC") LibItem m1=new Magazine(39,"mw",10,3,2006) this.b1.sameCatNo(33)->false this.b1.sameCatNo(77)->true this.c1.sameCatNo(33)->false this.m1.sameCatNo(39)->true ---------- ---------- |Solution| ---------- ---------- 1)Accessor-methods We could add to the interface LibItem "accessor-methods" headers that provide values of common fields // returns the catalog number of this item int getCatNo(); // returns the title of this item int getTitle(); // returns the due date of this item int getdueDate(); 2) The Visitor Pattern We add in the interface LibItem the following header methods //does this item have the given catalog number? boolean sameCatNo(int cNo); and then we must implement this methods in every class. For example in the class Book: //does this Book have the given catalog number? boolean sameCatNo(int cNo){ ... } ... and in the class CD: //does this CD have the given catalog number? boolean sameCatNo(int cNo){ ... } ... and in the class Magazine: //does this Magazine have the given catalog number? boolean sameCatNo(int cNo){ ... } 3) ***Abstraction*** But, we would like to indicate that the LibItem classes have something more in common, namely fields --- and possibly some methods as well. To do this we use 'inheritance' - a common super class that is extended by several subclasses. We also say that the subclasses extend the super class. The super class can declare fields and methods, just like any other class. If all methods can be defined in the super class, it becomes a class just like any other. So, we can modify the class definitions as follows: +--------------+ | LibItem | +--------------+ | / \ | +----------------------------+ | ALibItem | +----------------------------+ | int catNo | | String title | | int dueDate | +----------------------------+ | boolean same(ALibItem that)| +----------------------------+ / \ --- | ---------------------------------------- | | | +---------------+ +---------------+ +----------+ | Book | | CD | | Magazine | +---------------+ +---------------+ +----------+ | String author | | String artist | | int vol | +---------------+ +---------------+ | int no | +----------+ We change the shape of the arrows - the inheritance arrow in the official UML is shown as a solid line with an open triangle at the end, as opposed to the implementation arrow that is made of dashed lines and an open arrow. The classes are now defined as follows: // to represent a library item abstract class ALibItem implements LibItem{ int catNo; String title; int dueDate; ALibItem implements LibItem(int catNo, String title){ this.catNo=catNo; this.title=title;} //does this item have the given catalog number? boolean sameCatNo(int cNo){ return this.catNo == cNo; } } // to represent a book in a library class Book extends ALibItem { String author; Book(int catNo, String title, int dueDate, String author) { super(catNo, title, dueDate); this.author = author; } } // to represent a CD in a library class CD extends ALibItem { String artist; CD(int catNo, String title, int dueDate, String artist) { super(catNo, title, dueDate); this.artist = artist; } } // to represent a magazine in a library class Magazine extends ALibItem { int vol; int no; Magazine(int catNo, String title, int dueDate, int vol, int no) { super(catNo, title, dueDate); this.vol = vol; this.no = no; } } NOTE:The constructor in the classes Book, CD, and Magazine first calls the 'super' constructor and initializes the three common fields, then proceeds to initialize the remaining fields. The super constructor call --must be-- the first line in the body of the constructor in the subclass. A complete working code is included below. */ // to represent a library item interface LibItem{} abstract class ALibItem implements LibItem{ int catNo; String title; int dueDate; ALibItem(int catNo, String title, int dueDate){ this.catNo=catNo; this.title=title; this.dueDate=dueDate;} //does this item have the given catalog number? boolean sameCatNo(int cNo){ return this.catNo == cNo; } } // to represent a book in a library class Book extends ALibItem { String author; Book(int catNo, String title, int dueDate, String author) { super(catNo, title, dueDate); this.author = author; } } // to represent a CD in a library class CD extends ALibItem { String artist; CD(int catNo, String title, int dueDate, String artist) { super(catNo, title, dueDate); this.artist = artist; } } // to represent a magazine in a library class Magazine extends ALibItem { int vol; int no; Magazine(int catNo, String title, int dueDate, int vol, int no) { super(catNo, title, dueDate); this.vol = vol; this.no = no; } } class Examples{ ALibItem b1=new Book(77,"HtDP",2001,"MF"); ALibItem b2=new Book(33,"LPP",1944,"STX"); ALibItem c1=new CD(68,"Live",1992,"AC-DC"); ALibItem m1=new Magazine(39,"mw",10,3,2006); boolean test1 = (check this.b1.sameCatNo(33) expect false) && (check this.b1.sameCatNo(77) expect true) && (check this.c1.sameCatNo(33) expect false) && (check this.m1.sameCatNo(39) expect true); }