Chapter 9 – Designing Classes Chapter Goals Learn to identify side effects Know when to use method preconditions and postconditions Go in depth.
Download ReportTranscript Chapter 9 – Designing Classes Chapter Goals Learn to identify side effects Know when to use method preconditions and postconditions Go in depth.
Chapter 9 – Designing Classes
Chapter Goals
Learn to identify side effects Know when to use method preconditions and postconditions Go in depth a bit more on static (aka class) methods and fields Design programs the object-oriented way
9.3 Immutable Classes
Recall that accessor methods only retrieve information They do not change the state of the object Calling them multiple times in a row will yield same results Immutable Classes are classes that only have accessor methods
Example: String Class Advantages Do not have to worry about the dangers of handing off references in methods because there are no methods that can modify them.
Disadvantages Your objects are fixed once they are created.
9.4 Side Effects
Mutators are designed to change the internal data of the implicit parameter Side effect of a method: modifying externally observable data (explicit parameters or reference types)
public void transfer(double amount, BankAccount other) { balance = balance - amount; other.balance = other.balance + amount; // Modifies explicit parameter }
Best to avoid if possible (otherwise, document the effect thoroughly)
Other Side Effects
Why don’t we add a printBalance() method to BankAccount?
public void printBalance() { System.out.println("The balance is now $" + balance); }
Assumes the printing should be done to the screen Assumes the printing should be in English Makes this class dependent on the System class and PrintStream class You want to localize the input and output of your program to as few places as possible
How to minimize Side Effects?
Never modify explicit parameters to a method Treat them as constants
public void deposit(double amount) { amount = amount + balance; }
Pass By Value
Two ways to pass parameters Pass by reference – the memory location is sent, meaning that the data can be changed Pass by value – a copy of the memory location is created Java only uses pass by value Even objects are passed by value, since the reference is copied
Won’t work!
public class BankAccount { public void transferTo (BankAccount other, double amount) { balance = balance – amount; double newBalance = other.balance + amount; other = new BankAccount(newBalance); } }
}
Neither will this
class Q:
public void addResponse(String question) { String response = “I accept”; question = new String(question + response);
class R:
public void invite() { Q friend = new Q(); String invite = “Want to go to the dance?”; int inviteLength = invite.length(); do { friend.addResponse(invite); } while(invite.length() == inviteLength); }
}
class Q:
You would need to do this
public String addResponse(String question) { String response = “I accept”; return new String(question + response);
class R:
public void invite() { Q friend = new Q(); String invite = “Want to go to the dance?”; int inviteLength = invite.length(); do { invite = friend.addResponse(invite); } while(invite.length() == inviteLength); }
9.5 Preconditions
Precondition: Requirement that the caller of a method must meet Publish preconditions so the caller won't call methods with bad parameters
/** Deposits money into this account.
@param amount the amount of money to deposit (Precondition: amount >= 0) */
Preconditions
Typical use: To restrict the parameters of a method To require that a method is only called when the object is in an appropriate state If precondition is violated, method is not responsible for computing the correct result. It is free to do
anything
.
Handling Violations
Method does not have to behave correctly when preconditions are violated But what should be done?
Assume data is correct. Continue until the bad data causes another error (i.e divide by zero)
Throw an exception
(Chapter 15) if a condition is violated. The control is shifted to an exception handler • Runtime error messages are all exceptions
Another option
Method can do an assertion check
assert amount >= 0; balance = balance + amount;
To enable assertion checking:
java -enableassertions MyProg
You can turn assertions off after you have tested your program, so that it runs at maximum speed
Common error
Returning silently on error is hard to detect and debug
if (amount < 0) return; // Not recommended; hard to debug balance = balance + amount;
Postconditions
Condition that is true after a method has completed. This is the designer’s duty (as opposed to preconditions being the caller’s duty) If method call is in accordance with preconditions, it must ensure that postconditions are valid
There are two kinds of postconditions: The return value is computed correctly The object is in a certain state after the method call is completed (mutators)
/** Deposits money into this account. @param amount the amount of money to deposit (Precondition: amount >= 0) (Postcondition: getBalance() >= 0) */
Don't document trivial postconditions that repeat the @return clause Formulate pre- and postconditions only in terms of the interface of the class
getBalance() >= 0 // is a better postcondition than balance >= 0
Contract
Think of pre and postconditions as a contract If caller fulfills precondition, method must fulfill postcondition.
Static Fields (Class Fields)
Stores a field outside of any particular instance (object) Only one copy of a field that is
shared
by all instances of a class Minimize use of static for OO programs
Static Methods (Class Methods)
Can be invoked without creating an instance.
Can only access
explicit
parameters,
class
fields, and
class
methods.
main
method must be static
Field Modifier choices
3.
4.
5.
1.
2.
For each field: Choose data type and identifier.
is it a constant?
if so, add
final
modifier does it require a different value for each instance? if not, add
static
modifier is it safe to be directly accessible to methods in other classes?
if so,
public
else
private
is the value known?
if it is static, initialize now, otherwise initialize it in the constructor
Method Modifier choices
3.
4.
1.
2.
For each method: Choose identifier, return type, and parameters does it need to access any instance (non static) fields or instance methods? if not, add
static
modifier Must it be called from methods in other classes?
if so, must be
public
else make it
private
is it safe to be overridden? (chapter 13) if not, add
final
modifier
Why make fields static?
so that only one copy of the value is stored (all instances share the same copy)
Why make methods static?
so that the method is accessible without creating an instance Note: Can only do this if the method only requires explicit parameters or static fields.
Why write a method that does not operate on an object?
Common reason: encapsulate some computation that involves only numbers. Numbers aren't objects, you can't invoke methods on them. E.g., x.sqrt() can never be legal in Java
public class Financial { public static double percentOf(double p, double a) { return (p / 100) * a; } // Other methods can be added }
calculateMultiplier from assignment 2 probably should have been static. Why?
Call with class name instead of object:
double tax = Financial.percentOf(taxRate, total);
main is static –there aren't any objects yet
public class Financial { public static double percentOf(double p, double a) { return (p / 100) * a; } public static void main(String[] args) { double percent = percentOf(20.0,10.0); System.out.println(percent+” is 20% of 10”); } }
Static Fields
Three ways to initialize: Do nothing. Field is with 0 (for numbers), false (for boolean values), or null (for objects) Use an explicit initializer
BankAccount { . . .
private static int lastAssignedNumber = 1000; // Executed once, when class is loaded }
Use a static initialization block in a method
Scope Of Local Variables
Scope of variable: Region of program in which the variable can be accessed Scope of a local variable extends from its declaration to end of the block that encloses it Sometimes the same variable name is used in two methods:
public class RectangleTester { public static double area(Rectangle rect) {
double r
= rect.getWidth() * rect.getHeight(); return r; } public static void main(String[] args) {
Rectangle r
= new Rectangle(5, 10, 20, 30); double a = area(r); System.out.println(r); } }
Scope of a local variable cannot contain the definition of another variable with the same name
Rectangle r
= new Rectangle(5, 10, 20, 30); if (x >= 0) {
double r
. . .
= Math.sqrt(x); // Error–can't declare another variable //called r here }
However, can have local variables with identical names if scopes do not overlap
if (x >= 0) { { double r = Math.sqrt(x); . . .
} // Scope of r ends here else Rectangle r = new Rectangle(5, 10, 20, 30); // OK–it is legal to declare another r here . . .
}
Fields have class scope: You can access all fields in any method of the class. Must
qualify
public fields outside scope.
Math.PI
harrysChecking.BANK_FEE
Inside a method, no need to qualify fields or methods that belong to the same class An unqualified instance field or method name refers to the this parameter
public class BankAccount { public void transfer(double amount, BankAccount other) { withdraw(amount); } . . .
//same as: this.withdraw(amount); other.deposit(amount); }
A local variable can
shadow
name a field with the same Local scope wins over class scope
public class Coin { private String name; private double value; // Field with the same { exchangeRate) . . .
return value; //name public double getExchangeValue(double double value; // Local variable } }
Packages
Package: Set of related classes To put classes in a package, you must place a line
package packageName;
as the first instruction in the source file containing the classes Package name consists of one or more identifiers separated by periods
For example, to put the Financial class introduced into a package named
com.horstmann.bigjava
, the Financial.java file must start as follows:
package com.horstmann.bigjava; public class Financial { . . .
}
Default
Default package has no name, no package statement
9.1 Choosing Classes
Division of labor: Methods = functions Classes/objects = entities A class represents a single concept from the problem domain Name for a class should be a noun that describes concept
Good classes
Concepts from mathematics:
Point Rectangle Ellipse
Concepts from real life
BankAccount CashRegister
Class = concept
Recall that a class represents a concept Some are concrete (i.e. real world) • • • • A bank account Rental items Database of items Pile Others are abstract • • Scanner Streams, Math
Good Classes
Actors (end in -er, -or) –objects do some kinds of work for you
Scanner Random // better name: RandomNumberGenerator
Utility classes –no objects, only static methods and constants
Math
Degenerate case of a class: only main() method (like application and test classes)
Bad Classes
Don't turn actions into classes:
Paycheck
is better name than
ComputePaycheck
The name can tip you off when you are on wrong track Representing a PayCheck is more useful than only designing a class that seems to compute a pay check
Practice Question class Die
What are the
operations
use the die?
needed to What
data
are needed to represent the concept of a die?
fields
UML diagram for class Die
The name of the class appears at the top data type
Die
+ means public - means private -numSides : int -currentValue : int static fields and methods are underlined constructors and methods +Die(int) +roll() : void +getValue() : int parameter type (sometimes name too to help understand what it does) return type
Figure from Adv Topic 17.1
17.2 Discovering Classes
Recall that part of the design phase is deciding what structures you need to solve a task In OOD this translates into 3 steps Discover classes Determine the responsibilities of each class Describe relationships between each class
Simple rule
Look for nouns in task description (specs) Obviously not all nouns are classes But can create a list of
candidate classes
Then determine which ones are useful Cross them off your list
Key points
Class represents set of objects with the
same behavior
Entities with
multiple occurrences
in problem description are good candidates for objects Find out what they have in common Design classes to capture commonalities Not all nouns need a new class Address needs to represented, do we need a new class or can we use a String?
Could have argument for both – but must balance generality with limiting design
Behavior
After set of classes have been sketched up, define behavior/purpose, of each class Verbs = methods
CRC Card
Describes a
c
lass, its
r
esponsibilities, and its
c
ollaborators Use an index card for each class Pick the class that should be responsible for each method (verb) Write the responsibility onto the class card Indicate what other classes are needed to fulfill responsibility (collaborators)
9.2 Cohesion
A class should represent a single concept The public interface of a class is
cohesive
if all of its features are related to the concept that the class represents methods and public constants/variables should all relate to the central idea of the class
}
Cohesion
This class lacks cohesion:
public class CashRegister{ public void enterPayment(int dollars, int quarters, int dimes, int nickels, int pennies) . . .
public static final double NICKEL_VALUE = 0.05; public static final double DIME_VALUE = 0.1; public static final double QUARTER_VALUE = 0.25; . . .
What is the problem with this lack of cohesion?
More confusion Ties the role of a cash register to the value of the coins What if we wanted to sell this cash register to other countries?
Solution
CashRegister, as described above, involves two concepts:
cash register
and
coin
Solution: Make two classes:
public class Coin{ public Coin(double aValue, String aName){ . . . } public double getValue(){ . . . } . . .
} public class CashRegister{ public void enterPayment(int coinCount, Coin coinType) { . . . } . . .
}
Coupling
A class
depends
on another if it uses objects of that class
CashRegister
depends on
Coin
the value of the payment to determine
Coin
does not depend on
CashRegister
High Coupling = many class dependencies
Minimize coupling to minimize the impact of interface changes To visualize relationships draw class diagrams UML: Unified Modeling Language. Notation for object-oriented analysis and design
17.3 Relationships Between Classes
Good practice to document relationship between classes Can uncover common behavior Divide uncommon classes among programming teams We have learned about inheritance as a relationship 4 total important relationships We’ve come across 2 so far, 2 more in upcoming chapters
Dependency
Dependency occurs when a class uses another class methods
Uses
relationship Example: many of our applications depend on the
Scanner
class to read input
Aggregation
Aggregation is a stronger form of dependency
Has-a
relationship Objects of one class contain references to objects of another class Use an instance variable Class A aggregates class B if A contains an instance field of type B Arrow is drawn from the contained class to the class that contains it Car aggregates Tire Car Tire
Relationship
Inheritance (Chapter 13) Interface Implementation (Chapter 11)
Symbol Aggregation Dependency Line Style
Solid Dotted
Solid Dotted Arrow Tip
Triangle Triangle
Diamond Open
17.1 Software Life Cycle
Software Life Cycle: all activities from initial analysis until obsolescence Formal process for software development Describes phases of the development process Gives guidelines for how to carry out the phases
5 phases
1.
2.
3.
4.
5.
Analysis Design Implementation Testing Deployment / Operation
5 phases
2.
3.
4.
5.
1.
Analysis – What is the program supposed to do?
Output: requirements document Design Implementation Testing Deployment / Operation
5 phases
3.
4.
5.
1.
2.
Analysis Design – How is it going to be implemented?
Output: Design document (UML/CRC cards/Javadocs) Implementation Testing Deployment / Operation
5 phases
1.
2.
3.
4.
5.
Analysis Design Implementation – Write the code (edit/compile/run) Output: Completed program Testing Deployment / Operation
5 phases
1.
2.
3.
4.
5.
Analysis Design Implementation Testing – Verify that it works correctly Output: Test cases passed (unit/system) Deployment / Operation
5 phases
1.
2.
3.
4.
5.
Analysis Design Implementation Testing Deployment / Operation – Maintain the program Output: Public product, patches, new features
Perfect World
In a perfect world, everything would flow perfectly in this process Output from one phase signifies it is complete and can start the next phase Doesn’t really work You’ve probably noticed this Was anyone’s A5 perfect?
Have your tests every worked completely?
Waterfall Model
Problems with Waterfall Model
Specs usually have flaws Contradictions Non-thorough (what needs to happen on bad input?) Design too complicated, implementation flawed Testing incomplete
Spiral Model
Breaks development process down into multiple phases Early phases focus on the construction of
prototypes
Shows some aspects of the final product quick implementation Lessons learned from development of one prototype can be applied to the next iteration Problem: can lead to many iterations, and process can take too long to complete high cost and low throughput
Spiral
Design Analysis
Prototype 2 Prototype 1 Final Product
Deployment Testing Implementation
Extreme Programming
Approach suggested by Kent Back in 1999 Goal: Simplicity Cut out formal structure Focus on set of practices to make programming more efficient and satisfactory
Practices
Realistic planning
: Customers make business decisions (what should it look like?), programmers make technical ones (how do we that?)
Small Releases
– start small, update later
Metaphor
– common story among programmers
Simplicity
– simple solution is best
Testing
– by everyone!
Refactoring
– restructure as you go
Cont.
Pair Programming
Collective Ownership
Continuous Organization
40-hour week
On-site customer
Coding standards