/* --- CSU213 Spring 2005 Lecture Notes --------- Copyright 2005 Viera K. Proulx Lecture 5: Method to the Madness ... */ /* Goals: - learn to define and use methods in simple classes - design recipe for methods Introduction: So far we have considered only data. We have not computed anything, did not ask questions about the objects we defined, in short, we have not written any programs. Part of the reason is that the functions in languages like Java need to know what kind of data are they consume and what kind of data they produce. In Scheme, this was only specified in a comment, in other languages, like Java, the programmer must explicitly write down what is the type of each function argument. The functions in Java are always associated with some class of data --- and are called either memeber functions, or more often 'methods'. Methods in a class are designed to answer questions about instances of this class, or produce new objects in the class from existing objects. So we may have a method in the class Book which determines whether this book has a given title, or the class that represents geometric chapes may have a method which produces a new shape of the same size and color as the original one, but moved to a new location. However, the design of methods follows the same design recipe we have learned in HtDP. Example: Instead of books in a library, we will go to a bookstore to buy books. That means, besides the title and the name of the author,each book also has a price (in whole cents). Our bookstore sells all hardcovers at 20% off the list price. Our first taks is to compute the selling price of a book. Here is the class that represents books: */ /* +-------------------+ | Book | +-------------------+ | String title | | String author | | int price | | boolean hardcover | +-------------------+ */ // to represent a book in a bookstore class Book { String title; String author; int price; boolean hardcover; Book(String title, String author, int price, boolean hardcover) { this.title = title; this.author = author; this.price = price; this.hardcover = hardcover; } // add the methods here /* Before we design any methods, we make a couple of examples of books: Book ch = new Book("the Cat in a Hat", "Dr Seuss", 1500, true); Book dvc = new Book("Da Vinci Code", "Dan Brown", 3000, true); Book cr = new Book("Catcher in a Rye", "JD Salinger", 800, false); The first method we design computes the sale price of the book. 1. Problem analysis and data defeinitions: The only piece of informaton the method needs is the instance of the class Book for which we are computing the sale price. It will produce an integer value that represents the sale price. 2. Purpose and contract (we will call it 'header'): // compute the sale price of this book int salePrice(){...} The int at the beginning specifies what type of data the method produces. The parentheses after the name of the method hold the list of parameters for this method - but there are none specified. That is, because the book for which we are computing the price is already known -- as 'this' -- as we will see in the examples. 3. Examples: we expect the prices of the three books to be $12, $24, and $8. This is written as test cases inside of the class Examples: boolean test1 = this.ch.salePrice() == 1200; boolean test2 = this.dvc.salePrice() == 2400; boolean test3 = this.cr.salePrice() == 800; We see, that in each case the instance of the book for which we are computing the price appears before the method, followed by a '.' 'this' book in our purpose statement refer to this implicit parameter. 4. Template: The template lists all parts of data available for the computation inside of the body of the method. Even though we have no parameters, the Book object which invoked the method contains several parts, and so the template will be: ... this.title ... ... this.author ... ... this.price ... where 'this' refers to the instance which invoked the method. Only 'this.price' is relevant for our method, and the body becomes: return this.price - this.price / 5; The complete method is shown below: */ // compute the sale price of this book int salePrice(){ if (this.hardcover) return this.price - this.price / 5; else return this.price; } } /* We copy the examples of data and of the method invocation into the ExamplesBooks class: */ class ExamplesBooks{ ExamplesBooks() {} Book ch = new Book("the Cat in a Hat", "Dr Seuss", 1500, true); Book dvc = new Book("Da Vinci Code", "Dan Brown", 3000, true); Book cr = new Book("Catcher in a Rye", "JD Salinger", 800, false); boolean test1 = this.ch.salePrice() == 1200; boolean test2 = this.dvc.salePrice() == 2400; boolean test3 = this.cr.salePrice() == 800; } /* Next, we want to figure out whether we have enough money to buy a particular book. 1. Problem analysis and data analysis: The method consumes the amount of money we have and produces a boolean value. 2. Purpose and header: // ddetermine whether the given amount is enough to buy this book boolean enoughMoney(int amount) {...} 3. Examples: ch.enoughMoney(2000) == true dvc.enoughMoney(2000) == false 4. Template: --- we can now add the method we already defined --- ... this.title ... ... this.author ... ... this.price ... ... this.salePrice() ... 5. Body: return this.salePrice() <= amount; so that the whole method becomes: // determine whether the given amount is enough to buy this book boolean enoughMoney(int amount) { return this.salePrice() <= amount; } 6. Tests: -- to be inserted in the ExamplesBooks class: boolean test4 = this.ch.enoughMoney(2000) == true; boolean test5 = this.dvc.enoughMoney(2000) == false; */ /* Finally, we want to figure out whether one book costs less than another one. 1. Problem analysis and data analysis: The method consumes one additional book and produces a boolean value. 2. Purpose and header: // determine whether this book is cheaper than the given book boolean cheaperThan(Book that) {...} 3. Examples: ch.cheaperThan(dcv) == true dvc.cheaperThan(ch) == false 4. Template: --- we can now add the methods we already defined --- ... this.title ... ... this.author ... ... this.price ... ... this.salePrice() ... ... this.enoughMoney(int amount) ... --- and also all these =fields and methods for 'that' book --- ... that.title ... ... that.author ... ... that.price ... ... that.salePrice() ... ... that.enoughMoney(int amount) ... The first part of the template should be retained at the end of the class as it grows as more methods are added to the class. It can be just copied and pasted into the method body as it is being developed, and erased once not needed. The second part is specific to this method, and so should be written there. 5. Body: return this.cheaperThan() <= that.salePrice(); so that the whole method becomes: // determine whether this book is cheaper than the given book boolean cheaperThan(Book that) { return this.salePrice() <= that.salePrice(); } 6. Tests: -- to be inserted in the ExamplesBooks class: boolean test6 = this.ch.cheaperThan(this.dvc) == true; boolean test7 = this.dvc.cheaperThan(this.ch) == false; */ /*Here is our code all together: +-------------------+ | Book | +-------------------+ | String title | | String author | | int price | | boolean hardcover | +-------------------+ */ // to represent a book in a bookstore class Book2 { String title; String author; int price; boolean hardcover; Book2(String title, String author, int price, boolean hardcover) { this.title = title; this.author = author; this.price = price; this.hardcover = hardcover; } // compute the sale price of this book int salePrice(){ if (this.hardcover) return this.price - this.price / 5; else return this.price; } // determine whether the given amount is enough to buy this book boolean enoughMoney(int amount) { return this.salePrice() <= amount; } // determine whether this book is cheaper than the given book boolean cheaperThan(Book2 that) { return this.salePrice() <= that.salePrice(); } } class ExamplesBooks2{ ExamplesBooks2() {} Book2 ch = new Book2("the Cat in a Hat", "Dr Seuss", 1500, true); Book2 dvc = new Book2("Da Vinci Code", "Dan Brown", 3000, true); Book2 cr = new Book2("Catcher in a Rye", "JD Salinger", 800, false); boolean test1 = this.ch.salePrice() == 1200; boolean test2 = this.dvc.salePrice() == 2400; boolean test3 = this.cr.salePrice() == 800; boolean test4 = this.ch.enoughMoney(2000) == true; boolean test5 = this.dvc.enoughMoney(2000) == false; boolean test6 = this.ch.cheaperThan(this.dvc) == true; boolean test7 = this.dvc.cheaperThan(this.ch) == false; }