Chapter 7 Designing Classes Goals To learn how




















- Slides: 20
Chapter 7 Designing Classes Goals · · · · To learn how to choose appropriate classes to implement To understand the concepts of cohesion and coupling To minimize the use of side effects To document the responsibilities of methods and their callers with preconditions and postconditions To understand the difference between instance methods and static methods To introduce the concept of static fields To understand the scope rules for local variables and instance fields To learn about packages
Choosing Classes · A class represents a single concept · Concepts from mathematics: Point Rectangle Ellipse · Concepts from real life Bank. Account Purse · Actors (end in -er, -or) String. Tokenizer Random (better called Random. Number. Generator) · Utility classes--no objects, only static methods Math
Cohesion · Cohesive = public interface closely related to the single concept that the class represents · The following class lacks cohesion: public class Purse { public Purse(){. . . } public void add. Nickels(int count){. . . } public void add. Dimes(int count){. . . } public void add. Quarters(int count){. . . } public double get. Total(){. . . } public static final double NICKEL_VALUE =0. 05; public static final double DIME_VALUE =0. 1; public static final double QUARTER_VALUE =0. 25; . . . }
Cohesion · Two concepts: purse and coin · Solution: Make two classes: – public class Coin { public Coin(double a. Value, String a. Name){. . . } public double get. Value(){. . . } } – public class Purse { public Purse(){. . . } public void add(Coin a. Coin){. . . } public double get. Total(){. . . } }
Coupling · A class depends on another if it calls one of its methods · Purse depends on Coin because it calls get. Value on coins · Coin does not depend on Purse · High Coupling = many class dependencies · Minimize coupling to minimize the impact of interface changes Dependency Relationship between Purse and Coin Classes
High and Low Coupling between Classes
Accessor and Mutator Classes · Accessor: does not change the state of the implicit parameter (e. g. get. Balance) · Mutator: changes the state of the implicit parameter (e. g. deposit ) · Rule of thumb: Mutator should return void · Immutable class: all methods are accessors (e. g. String) • Side Effect: any observable change outside the implicit parameter – Example: modify implicit parameter – public void transfer(double amount, Bank. Account other) { balance = balance - amount; other. balance = other. balance + amount; }
Common Error: Can't Modify Primitive Type Parameters • Example – void transfer(double amount, double other. Balance) { balance = balance - amount; other. Balance = other. Balance + amount; } • Won't work Scenario: – double savings. Balance = 1000; harrys. Checking. transfer(500, savings. Balance)
Modifying a Numeric Parameter has No Effect on Caller
Preconditions · 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) */ · 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 · Method can do anything if called when precondition not fulfilled
Preconditions • Method may throw exception if precondition violated if (amount < 0) throw new Illegal. Argument. Exception(); balance = balance + amount; • Nicer to throw exception than to silently muddle through if (amount < 0) return; // don't do this balance = balance + amount; • Method doesn't have to test for precondition. (Test may be costly) // no test--that's ok // if this makes the balance negative, // it's the caller's fault balance = balance + amount
Postconditions · Condition that's true after a method has completed. /** Deposits money into this account. (Postcondition: get. Balance() >= 0) @param amount the amount of money to deposit (Precondition: amount >= 0) */ · Don't document trivial postconditions that repeat the @return clause · Contract: If caller fulfills precondition, method must fulfill postcondition
Static Methods · Every method must be in a class · Some methods have no implicit parameter · E. g. if all parameters are primitive class Numeric { public static boolean approx. Equal(double x, double y) {. . . } } · Call with class name instead of object: if (Numeric. approx. Equal(a, b)). . . · main is static--there aren't any objects yet · Too many static methods are a sign of too little OO
Static Fields • One field per class, shared by all objects of the class public class Bank. Account {. . . private double balance; private int account. Number; private static int last. Account. Number; } public Bank. Account() { last. Assigned. Number++; // increment static field account. Number = last. Assigned. Number; // set instance field } • Minimize the use of static fields. (Static final fields are ok. )
A Static Field and Instance Fields
Scope · Scope of variable: region of program where you can refer to the variable by its name · Local variable scope: from definition to end of block · Class scope: all methods of the class · Must qualify public members outside scope, e. g. Math. sqrt · Overlapping scope: local scope wins over class scope public class Coin { public void draw(Graphics 2 D g 2) { String name = "Sans. Serif"; // local scope g 2. set. Font(new Font(name, . . . )); // local name g 2. draw. String(this. name, . . . ); // field name } private String name; // class scope. . . }
Packages
Placing Classes into Packages · · To place classes in package, start file with packagename; · • package com. horstmann. bigjava; public class Numeric {. . . } · Default package has no name, no package statement Package names should be unambiguous Recommendation: · start with reversed domain name org. omg. CORBA com. horstmann. bigjava · Path name should match package name com/horstmann/bigjava/Numeric. java · Path name starts with class path · export CLASSPATH=/home/walters: .
Importing Packages • Can always use class without importing java. awt. Color background. Color = new java. awt. Color(. . . ); • Tedious to use fully qualified name Import lets you use shorter class name import java. awt. Color; . . . Color background. Color = new Color(. . . ); • Can import all classes in a package import java. awt. *; • Never need to import java. lang
Base Directories and Subdirectories for Packages