Download presentation
Presentation is loading. Please wait.
Published byShannon Weaver Modified over 8 years ago
1
Guidelines for class design Horstmann ch. 3.2-3.6 Noter ch.1.1
2
Guidelines for class design Encapsulation Programming by contract Quality of class interface
3
Encapsulation no public instance variables accessors and mutators
4
One class – several implementations Example Day class –Day encapsulates a day in a fixed location –Use Gregorian calendar Answer questions such as –How many days are there between now and the end of the year? –What day is 100 days from now? Class Day: Custom class, for teaching/learning purpose Use the standard library classes, not this class, in your own programs
5
Designing a Day class Constructor Day(int year, int month, int date) Accessors getYear, getMonth, getDate Other methods –daysFrom computes number of days between two days: int n = today.daysFrom(birthday); –addDays computes a day that is some days away from a given day: Day later = today.addDays(999);
6
Day class: Implementation 1 Straightforward implementation: private int year private int month private int date addDays/daysFrom tedious to implement –April, June, September, November have 30 days –February has 28 days, except in leap years it has 29 days –All other months have 31 days –Leap years are divisible by 4, except after 1582, years divisible by 100 but not 400 are not leap years –There is no year 0; year 1 is preceded by year -1 –In the switchover to the Gregorian calendar, ten days were dropped: October 15, 1582 is preceded by October 4
7
Day class: Implementation 2 For greater efficiency, use Julian day number –Used in astronomy –Number of days since Jan. 1, 4713 BCE –May 23, 1968 = Julian Day 2,440,000 private int julian; Greatly simplifies date arithmetic public int daysFrom(Day other) { return julian - other.julian; } But constructor and accessor inefficient
8
No public instance variables Public instance variables would have blocked change of implementation –Can't just use text editor to replace all d.year with d.getYear() –How about d.year++? d = new Day(d.getYear() + 1, d.getMonth(), d.getDay()) –Ugh--that gets really inefficient in Julian representation Don't use public fields, even for "simple" classes
9
QUIZ In which lines should visibility modifier be changed? 1.none 2.a 3.b 4.c 5.a+b 6.a+c 7.b+c 8.a+b+c 9.I don’t know public class Measures { a) public static final int SIZE = 3; b) public int length = 2; c) static int height = 4; }
10
Encapsulation no public instance variables accessors and mutators
11
Accessors and Mutators Accessor: Reads object state without changing it Mutator: Changes object state Class without mutators is immutable String is immutable
12
Don't Supply a Mutator for every Accessor Day has getYear, getMonth, getDate accessors Day does not have setYear, setMonth, setDate mutators These mutators would not work well –Example: Day deadline = new Day(2004, 1, 31); deadline.setMonth(2); // ERROR deadline.setDate(28); –Maybe we should call setDate first? Day deadline = new Day(2004, 2, 28); deadline.setDate(31); // ERROR deadline.setMonth(3); Immutability is useful
13
Sharing Mutable References References to immutable objects can be freely shared Don't share mutable references Example class Employee {... private Date hireDate; public Date getHireDate() { return hireDate; } } Pitfall: Employee harry =...; Date d = harry.getHireDate(); d.setTime(t); // changes Harry's state!!! Remedy: Use clone public Date getHireDate() { return (Date)hireDate.clone(); }
14
Separating Accessors and Mutators If we call a method to access an object, we don't expect the object to mutate Rule of thumb: Mutators should return void Example of violation: StringTokenizer t =...; String s = t.nextToken(); Yields current token and advances iteration What if I want to read the current token again?
15
Better interface: String getToken(); void nextToken(); Even more convenient: String getToken(); String nextToken(); // returns current Refine rule of thumb: Mutators can return a convenience value, provided there is also an accessor to get the same value
16
Side effects Accessor: no change to object Mutator: changes object state Side effect: change to another object –Parameter variable public void print(Employee e) {... e.getHireDate().setTime(t);... } Avoid side effects--they confuse users Good example, no side effect: a.addAll(b) mutates a but not b
17
QUIZ Which methods/constructors need be removed to make Bucket immutable? 1.none 2.a 3.b 4.c 5.a+b 6.a+c 7.b+c 8.a+b+c 9.I don’t know public class Bucket { private int size = 1; public Bucket(int s) {size=s;} public Bucket() {size++;} public void enlarge() { size++; } public Bucket enlarge() { return new Bucket(size+1); } a) c) b)
18
Programming by Contract Example: Queue Precondition Assertion Postcondition Implementation Invariant
19
Queue People waiting to be served in a cafeteria Processes waiting to get CPU-time on a computer food in a supermarket (at least the shop owner wants the customer to take the old stuff first)
20
Queue a queue consists of some objects placed one after the other (ordered). a new object may be placed in the rear, behind all the others the object in the front may be removed FIFO = First In First Out
21
Queue implementation 1 using ArrayList public class Queue { public Queue() { elements = new ArrayList (); } public void add(T x) { elements.add(x); } public T remove() { return elements.remove(0); } public T peek() { return elements.get(0); } public int size() { return elements.size(); } private ArrayList elements; }
22
Queue implementation 2 using Circular Array Circular: head, tail indexes wrap around Avoids inefficient shifting of elements
23
Programming by Contract Example: Queue Precondition Assertion Postcondition Implementation Invariant
24
Programming by contracts: Preconditions Caller attempts to remove element from empty Queue What should happen? –Queue can declare this as an error –Queue can tolerate call and return dummy value What is better? –Excessive error checking is costly –Returning dummy values can complicate testing Contract metaphor –Service provider must specify preconditions –If precondition is fulfilled, service provider must work correctly –Otherwise, service provider can do anything When precondition fails, service provider may –throw exception –return false answer –corrupt data
25
Precondition Precondition for remove: size() > 0 Queue implementation 1 using ArrayList: public T remove() { return elements.remove(0); } What happens if precondition not fulfilled? IndexOutOfBoundsException
26
Precondition Precondition for remove: size() > 0 Queue implementation 2 using circular array: public T remove() { T r = elements[head]; head = (head + 1) % elements.length; count--; return r; } What happens if precondition not fulfilled? Queue is corrupted
27
Exceptions in the Contract /**... @throws IllegalArgumentException if queue is empty */ public Message remove() { if (size() == 0) throw new IllegalArgumentException();... } Exception throw part of the contract Caller can rely on behavior Exception throw not result of precondition violation This method has no precondition
28
QUIZ For which precondition(s) does method peek satisfy its contract? 1.Any (no precondition needed) 2.PRECOND: size()>0; 3.PRECOND: add(…) has been called earlier 4.PRECOND: remove() has never been called 5.Some other distinct precondition 6.None (method is wrong for all preconditions) 7.I don’t know Public class Queue { private ArrayList elements; … /** @precondition PRECOND @return element at head of queue */ public T peek() { return elements.get(0); }
29
Programming by Contract Example: Queue Precondition Assertion Postcondition Implementation Invariant
30
Assertions Syntax: assert condition; assert condition : explanation; Throws AssertionError if condition false and checking enabled Enable assertion checking during testing with java -ea MyProg Useful for warning programmers about precondition failure
31
Assertion public Message remove() { assert size() > 0 : "violated precondition size() > 0";... }
32
Programming by Contract Example: Queue Precondition Assertion Postcondition Implementation Invariant
33
Postconditions Conditions that the service provider guarantees Example: add method @postcondition size() > 0 Postcondition of one call can imply precondition of another: q.add(m1); m2 = q.remove();
34
Pre- and post-conditions /** @param n integer @precondition n >= 0 @return integer squareroot a of n @postcondition a*a <= n && n < (a+1)*(a+1) */ public int intSquareRoot(int n) { assert n >= 0; int a = n; int b = 1; while (a>b) { a = (a+b)/2; b = n/a; } assert (a*a <= n && n < (a+1)*(a+1)); return a; } responsibility of caller to ensure precondition responsibility of implementor to ensure postcondition
35
QUIZ Which code at ? 1.A 2.B 3.C 4.D 5.None of A-D 6.Several of A-D boolean result = true; for (int i=1; i<list.size(); i++) if (list.get(i-1)>list.get(i)) result = false; else result = true; return result; for (int i=1; i<list.size(); i++) if (list.get(i-1)>list.get(i)) return false; else return true; for (int i=1; i<list.size(); i++) if (list.get(i-1)>list.get(i)) return false; return true; for (int i=0; i<list.size(); i++) if (list.get(i)>list.get(i+1)) return false; return true; /** @param list of numbers @return true precisely when list is sorted (in increasing order) */ public boolean sorted(List list) { } A B C D Postcondition! 7. I don’t know
36
Programming by Contract Example: Queue Precondition Assertion Postcondition Implementation Invariant
37
Condition that –involves details of particular implementation –is true after every constructor –is preserved by every method (if it's true before the call, it's again true afterwards) example: Box
38
Implementation invariant: class Box Methods for class Box: –fitsIn : Decide whether box fits within another box under 90 deg rotations –combine : Compute minimum enclosing box of this box and another box
39
Implementation invariant: class Box /** IMPLEMENTATION INVARIANT: x <= y <= z */ private int x,y,z; Invariant true after constructor public Box(int w, int h, int d) { x = w; y = h; z = d; while (x>y || y>z) { if (x>y) { int temp = x; x = y; y = temp; } if (y>z) { int temp = y; y = z; z = temp; } } sort dimensions to satisfy invariant represents height, width and depth
40
Implementation invariant: class Box Implementation invariant is true before method call –simplifies implementation public boolean fitsIn(Box b) { return ( x<=b.x && y<=b.y && z<=b.z ); } public Box combine(Box b) { return new Box(Math.max(x,b.x), Math.max(y,b.y), Math.max(z,b.z)); }
41
Implementation invariant: class Box Without implementation invariant: –Complicated implementation necessary –more error prone public boolean fitsIn(Box b) { return ( (x<=b.x && y<=b.y && z<=b.z) || (x<=b.x && z<=b.y && y<=b.z) || (y<=b.x && x<=b.y && z<=b.z) || (y<=b.x && z<=b.y && x<=b.z) || (z<=b.x && x<=b.y && y<=b.z) || (z<=b.x && y<=b.y && x<=b.z) ); }
42
QUIZ Which methods satisfy the invariant? 1.a and b 2.a only 3.b only 4.Neither 5.I don’t know public class Time { //INVARIANT 0 <= hour < 24 private int hour; public Time(int h) {hour = h;} public void increment() { hour = (hour+1) % 24; } public void increment2() { if (hour==23) hour = 0; else hour++; } a) b)
43
QUIZ Where should asserts be used to verify the invariant?? 1.A,B, C,D, E,F,G 2.A,B, C,D, E,G 3.B,D,F 4.B,D,G 5.A,B, C,D 6.B,D 7.Some other combination 8.I don’t know public class Time { //INVARIANT 0 <= hour < 24 private int hour; public Time(int h) { hour = h; } public void increment() { hour = (hour+1) % 24; } public int getMinutes() { int res = 60*hour; return result; } A F E G D C B
44
Quality of Class Interface Cohesion Completeness Convenience Clarity Consistency
45
Cohesion Class describes a single abstraction Methods should be related to the single abstraction Bad example: public class Mailbox { public addMessage(Message aMessage) {... } public Message getCurrentMessage() {... } public Message removeCurrentMessage() {... } public void processCommand(String command) {... }... } processCommand does not belong here
46
Completeness Support operations that are well-defined on abstraction Potentially bad example: Date Date start = new Date(); // do some work Date end = new Date(); How many milliseconds have elapsed? No such operation in Date class Does it fall outside the responsibility? After all, we have before, after, getTime
47
Convenience A good interface makes all tasks possible... and common tasks simple Bad example: Reading from System.in Why doesn't System.in have a readLine method? After all, System.out has println.
48
Clarity Confused programmers write buggy code Bad example: Removing elements from LinkedList Reminder: Standard linked list class LinkedList countries = new LinkedList (); countries.add("A"); countries.add("B"); countries.add("C"); Iterate through list: ListIterator iterator = countries.listIterator(); while (iterator.hasNext()) System.out.println(iterator.next());
49
Clarity Iterator between elements Like blinking caret in word processor add adds to the left of iterator (like word processor): Add X before B: ListIterator iterator = countries.listIterator(); // |ABC iterator.next(); // A|BC iterator.add("France"); // AX|BC To remove first two elements, you can't just "backspace" remove does not remove element to the left of iterator From API documentation: Removes from the list the last element that was returned by next or previous. This call can only be made once per call to next or previous. It can be made only if add has not been called after the last call to next or previous. Not clear
50
Consistency Related features of a class should have matching –names –parameters –return values –behavior Bad example: –String class s.equals(t) / s.equalsIgnoreCase(t) –But boolean regionMatches (int toffset, String other, int ooffset, int len) boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) –Why not regionMatchesIgnoreCase ?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.