270 likes | 382 Views
Lecture 8: Object-Oriented Design. Objectives. “Good object-oriented programming is really about good object-oriented design. And good OOD is all about making things easier for ourselves, as well as for our class users…” Class design Inheritance Interfaces. Part 1. Class design….
E N D
Objectives “Good object-oriented programming is really about good object-oriented design. And good OOD is all about making things easier for ourselves, as well as for our class users…” • Class design • Inheritance • Interfaces
Part 1 • Class design…
Class design rules #1 – #4 • These rules you probably already know: • "Classes should provide constructors" • to ensure initialization of fields • "Classes should provide methods to manipulate class fields" • e.g. bank Customer's getFormattedBalance( ) ormakeDeposit(amt) • "Classes should practice data-hiding, and control access otherwise" • use of private keyword, get & set methods for field access • "Classes should override toString( )" • to return appropriate string-based representation
Class design rule #5 • "Classes should override Equals( )" • enables object equality to be determined based on fields • Example: • students are equal if their IDs are the same if (s1.equals(s2)) ... public class Student { private int id; . . . public boolean equals(Object obj) { // make sure we are comparing apples to apples… if (obj == null || !(obj.getClass().equals(this.getClass()))) return false; // we know obj is a student but J# doesn't, so type-cast to Student so we can compare IDs… Student other = (Student) obj; return this.id == other.id; }
Class design rule #6 • "Classes that override Equals( ) should also override hashCode( )" • Java rule: equal objects must have equal hash codes • Solution? Base hashCode( ) on same field(s) as equals( ) • Example: • student's hash code is their ID! public class Student { private int id; . . . public int hashCode() { return this.id; // equal students will have same hash code! }
Part 2 • Inheritance…
Inheritance • One class may extend another class, inheriting all fields & methods: • Why do this? • Code reuse! Class B doesn't have to reinvent class A… • Design reuse! Class B "is-a" class A, and treated as such… public class B extends A { . . . }
Student firstName : StringlastName : Stringid : intgpa : double Student(fn, ln, id, gpa)get_firstName( ) : String . . . Freshman Sophomore Junior Senior Example • Student class hierarchy: super / base / parent sub / derived / child extends
Superclass design • Superclass can define members as private, protected, or public • Superclass can define common functionality for its subclasses • Superclass can define abstract methods for subclasses to implement public abstract class Student { protected String firstName, lastName; protected int id; protected double gpa; . . . public String getFormattedGPA() { java.text.DecimalFormat formatter; formatter = new java.text.DecimalFormat("0.00"); return formatter.format(this.gpa); } public abstract boolean meetsMinGPA(); }
Subclass design • Subclasses are responsible for: • calling their superclass's constructor • implementing any abstract methods public class Freshman extends Student { public Freshman(String fn, String ln, int id, double gpa) { super(fn, ln, id, gpa); } public boolean meetsMinGPA() { // freshman must maintain a GPA of 1.5 or greater... return this.gpa >= 1.5; } }
Polymorphism • Poly-whatism? • Polymorphism is about writing code in a general way • the more general the code, the more reusable in new situations • More formally: • Definition: polymorphism is when different types support the same operation, allowing the types to be treated similarly. • this allows the same code to work on a wider range of types • Example? • Student objects and meetsMinGPA( ) • next page…
Example: meetsMinGPA( ) • meetsMinGPA() is an example of a polymorphic method • defined in super class so all students support it • implemented in subclasses so each implementation may differ • Advantage? • the following code correctly checks *all* types of students to ensure they are meeting minimum GPA requirements! java.util.ArrayList students = new java.util.ArrayList(); students.add( new Freshman(…) ); // a Freshman is-a Student… students.add( new Junior(…) ); // a Junior is-a Student… . . . for (int i = 0; i < students.size(); i++) { Student s = (Student) students.get(i); if (!s.meetsMinGPA()) System.out.println("Min GPA violation: " + s); }//for
Dynamic binding • Dynamic binding is the technology that enables polymorphism • When you make a method call: • Java dynamically determines the type of the object, then • Java binds to ("calls") the correct method based on object's type . . . for (int i = 0; i < students.size(); i++) { Student s = (Student) students.get(i); if (!s.meetsMinGPA()) (1) What type of object: Freshman, Sophomore, Junior, or Senior? (2) Based on answer to (1), dynamically bind to (i.e. "call") the correct implementation of the meetsMinGPA( ) method in Freshman, Sophomore, Junior, or Senior.
Overriding equals, part 2 • Problem: • suppose we override equals( ) as discussed earlier, which requires that objects be exactly the same type to be equal • in this case, how do we search for students? java.util.ArrayList students = new java.util.ArrayList(); . . . int loc, id; Student s; id = ...; // id of student we are looking for… s = new ????????? ("", "", id, 0.0); // create temp object for search loc = students.indexOf(s); // linear search for actual student… What class do we use?
Overriding equals again… • Instead of requiring exactly the same types, check to make sure both objects inherit from Student… • we know "this" object does, just a matter of checking "obj"… public abstract class Student { private int id; . . . public boolean equals(Object obj) { // make sure we are comparing apples to apples… if (obj == null || !(obj.getClass().equals(this.getClass()))) return false; // we know obj is a student but J# doesn't, so type-cast to Student so we can compare IDs… Student other = (Student) obj; return this.id == other.id; } !(obj instanceof Student))
Linear search again… • Now you can search by creating any kind of object you want: • except for Student, which won't work since it's abstract java.util.ArrayList students = new java.util.ArrayList(); . . . int loc, id; Student s; id = ...; // id of student we are looking for… s = new Senior("", "", id, 0.0); // create temp object for search loc = students.indexOf(s); // linear search for actual student… if (loc >= 0) System.out.println("Found at location " + loc);
Part 3 • Interfaces & design by contract…
Motivation • We program by relying on "contracts" • i.e. agreements between objects • "Object X agrees to do Y, so I'll call X when I need to do Y" java.io.FileReader file = new java.io.FileReader("…"); java.io.BufferedReader reader = new java.io.BufferedReader(file); s = reader.readLine(); public class BufferedReader { . . . public String readLine() { . . . }
Design by contract • Design by contract formalizes this process • design first • implement second • Advantages? • encourages "think before you code" • ensures integration of classes in a large program • different classes supporting the same contract offer another means of polymorphic programming!
Interfaces • Interfaces are a formal way of specifying contracts • An interface = a set of method signatures • representing the contract between two or more parties • pure design, no data / code public interfaceSomeInterfaceName { public void Method1(); public int Method2(int x, String y); . . . }
"client"(object requesting service) Conceptual view • Here's how to visualize what's going on: Interface "server"(object performing service according to interface contract) • "client" uses interface to communicate with server • "server" implements interface to fulfill contract
Example • Sorting and binary search • These algorithms are a part of the Java Class Library • but use an interface to communicate with objects… object sort( ) object object object binarySearch( ) object object
(1) Comparable interface • Defines the comparison of two objects, returning an integer: • < 0 means this object < obj • = 0 means this object = obj • > 0 means this object > obj if (s1.compareTo(s2) < 0) ... public interfaceComparable { public int compareTo(Object obj); }
student student student (2) Objects implement Comparable • To fulfill contract, objects must implement Comparable: public abstract class Student implements Comparable { private int id; . . . public int compareTo(Object obj) { // make sure we are comparing apples to apples… Student other = (Student) obj; if (this.id < other.id) return -1; else if (this.id == other.id) return 0; else return 1; }
(3) Call sort() and binarySearch() • Now we can take advantage of these built-in algorithms: java.util.ArrayList students = new java.util.ArrayList(); students.add( new Freshman(…) ); students.add( new Junior(…) ); . . . java.util.Collections.sort(students); int loc, id; Student s; id = ...; // id of student we are looking for… s = new Senior("", "", id, 0.0); // create temp object for search loc = java.util.Collections.binarySearch(students, s); if (loc >= 0) System.out.println("Found at location " + loc);
Summary • Good OOP is all about good Object-Oriented Design • Java, J# and .NET all employ a great deal of OOD • effective use requires a solid understanding of OOD • e.g. linear search is built-in, but you need to implement equals() • e.g. sorting & binary search are built-in, but you need to implement Comparable and compareTo() • Inheritance & interfaces are important OOD tools • look for ways to create / exploit polymorphism