Refactoring Techniques for Conditional Statements: A Case Study, Study notes of Computer Science

A case study on various refactoring techniques for simplifying complex conditional statements. The techniques covered include decompose conditional, consolidate conditional expression, consolidate duplicate conditional fragments, remove control flag, and replace nested conditional with guard clauses. The document also introduces the concept of introduce null object to eliminate null checks and conditional statements.

Typology: Study notes

Pre 2010

Uploaded on 08/19/2009

koofers-user-gt0
koofers-user-gt0 🇺🇸

5

(1)

10 documents

1 / 19

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science
24 - Refactoring: Simplifying Conditional
Expressions and Method Calls
CMPSCI 220 (291A)
Programming Methodology
Spring 2009
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science 2
Goal for the week
Build your catalog of familiar refactorings
Increase sense of incremental nature of refactoring
Today: Conditional Expressions (REF 9) and Method
Calls (REF 10)
Next time: Composing methods (REF 6), Moving
features around (REF 7), Data (REF 8)
Later: Generalization (REF 12) and Big Refactorings
(REF 13)
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science 3
Simplifying Conditional Expressions
General motivation: Conditional logic (if and
switch statements) tends to get tricky
Decompose Conditional is a key: it separates the
switching logic from what happens
Some other refactorings address important special
cases
Usually replace switches with polymorphism
Introduce Null Object is a non-obvious case of that
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science 4
Decompose Conditional
Before:
if (date.before(SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;
else charge = quantity * _summerRate;
After:
if (notSummer(date))
charge = winterCharge(quantity);
else charge = summerCharge(quantity);
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science 5
Decompose Conditional
Motivation: Reasons why things happen get
obscured in details of condition(al)s
Mechanics
Extract condition to its own method
Extract then and else parts to their own methods
While the methods are often short, just the use of
names like notSummer and winterCharge make the
code much clearer
U
UNIVERSITY OF
NIVERSITY OF M
MASSACHUSETTS
ASSACHUSETTS, A
, AMHERST
MHERST
Department of Computer Science
Department of Computer Science 6
Consolidate Conditional Expression
Combine sequence of tests with same result:
Before:
double disabilityAmount () {
if (_seniority < 2) return 0;
if (_monthsDisabled > 12) return 0;
if (_isPartTime) return 0;
// compute disability amount …
After:
double disabilityAmount() {
if (isNotEligibleForDisability()) return 0;
// compute disability amount …
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13

Partial preview of the text

Download Refactoring Techniques for Conditional Statements: A Case Study and more Study notes Computer Science in PDF only on Docsity!

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science

24 - Refactoring: Simplifying Conditional

Expressions and Method Calls

CMPSCI 220 (291A)

Programming Methodology

Spring 2009

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 2

Goal for the week

„ Build your catalog of familiar refactorings

„ Increase sense of incremental nature of refactoring

„ Today: Conditional Expressions (REF 9) and Method

Calls (REF 10)

„ Next time: Composing methods (REF 6), Moving

features around (REF 7), Data (REF 8)

„ Later: Generalization (REF 12) and Big Refactorings

(REF 13)

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 3

Simplifying Conditional Expressions

„ General motivation: Conditional logic ( if and

switch statements) tends to get tricky

„ Decompose Conditional is a key: it separates the

switching logic from what happens

„ Some other refactorings address important special

cases

„ Usually replace switches with polymorphism

„ Introduce Null Object is a non-obvious case of that

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 4

Decompose Conditional

Before:

if (date.before(SUMMER_START) || date.after(SUMMER_END))

charge = quantity * _winterRate + _winterServiceCharge;

else charge = quantity * _summerRate;

After:

if (notSummer(date))

charge = winterCharge(quantity);

else charge = summerCharge(quantity);

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 5

Decompose Conditional

„ Motivation: Reasons why things happen get

obscured in details of condition(al)s

„ Mechanics

„ Extract condition to its own method

„ Extract then and else parts to their own methods

„ While the methods are often short, just the use of

names like notSummer and winterCharge make the

code much clearer

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 6

Consolidate Conditional Expression

Combine sequence of tests with same result:

Before:

double disabilityAmount () {

if (_seniority < 2) return 0;

if (_monthsDisabled > 12) return 0;

if (_isPartTime) return 0;

// compute disability amount …

After:

double disabilityAmount() {

if (isNotEligibleForDisability()) return 0;

// compute disability amount …

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 7

Consolidate Conditional Expression

„ Motivations:

„ Clarifies that the sequence is really one check of an “or” of conditions „ Often sets the stage for Extract Method

„ Mechanics:

„ The conditions must not have side-effects. „ Replace the string of ifs with one if using logical operators „ Compile and test „ Consider applying Extract Method to the result

„ Note: Can do the same thing with and-ed conditionals, etc.

„ Can sometimes use a ternary (? :) expression in a return

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 8

Consolidate Duplicate Conditional

Fragments

Before:

if (isSpecialDeal()) { total = price * 0.95; send(); } else { total = price * 0.98; send(); }

After:

if (isSpecialDeal()) { total = price * 0.95; } else { total = price * 0.98; } send();

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 9

Consolidate Duplicate Conditional

Fragments

„ Also works for common code at the beginning

„ Motivation: clarifies what varies and what stays the

same between the different cases

„ If there is more than one statement in common,

consider extracting it into a method

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 10

Remove Control Flag

„ There is a variable acting as a control flag for a

series of boolean expressions; use break or return

instead.

„ Motivation:

„ Code arises from one-entry/one-exit style of coding

„ As usual, refactoring improves clarity

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 11

Remove Control Flag

„ Generic structure being replaced:

set done to false while not done if (condition) do something set done to true next step of loop

„ Mechanics

„ Determine the value that gets you out „ Replace assignments of that value with break/continue

„ Compile and test after each replacement

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 12

Remove Control Flag

„ Generic structure being replaced:

set done to false while not done if (condition) do something set done to true next step of loop

„ Alternate refactoring

„ Extract the logic into a method „ Determine the value that gets you out „ Replace assignments of that value with a return „ Compile and test after each replacement

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 19

Remove Control Flag:

Example 2 – After Extract Method

void checkSecurity (String[] people) { String found = foundMiscreant(people); someLaterCode(found); } String foundMiscreant (String[] people) { String found = “”; for (String person : people) { if (found.equals(“”)) { if (person.equals(“Don”)) { sendAlert(); found = “Don”; } if (person.equals(“John”)) { sendAlert(); found = “John”; } } } return found; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 20

Remove Control Flag:

Example 2 – After first return

String foundMiscreant (String[] people) { String found = “”; for (String person : people) { if (found.equals(“”)) { if (person.equals(“Don”)) { sendAlert(); return “Don”; } if (person.equals(“John”)) { sendAlert(); found = “John”; } } } return found; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 21

Remove Control Flag:

Example 2 – After second return

String foundMiscreant (String[] people) { String found = “”; for (String person : people) { if (found.equals(“”)) { if (person.equals(“Don”)) { sendAlert(); return “Don”; } if (person.equals(“John”)) { sendAlert(); return “John”; } } } return found; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 22

Remove Control Flag:

Example 2 – Remove flag variable

String foundMiscreant (String[] people) { String found = “”; for (String person : people) { if (found.equals(“”)) { if (person.equals(“Don”)) { sendAlert(); return “Don”; } if (person.equals(“John”)) { sendAlert(); return “John”; } } } return “”; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 23

Remove Control Flag:

Example 2 – End

String foundMiscreant (String[] people) { for (String person : people) { if (person.equals(“Don”)) { sendAlert(); return “Don”; } if (person.equals(“John”)) { sendAlert(); return “John”; } } return “”; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 24

Replace Nested Conditional with

Guard Clauses

Normal path not clear:

double getPayAmount () { double result; if (_isDead) result = deadAmount(); else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; } return result; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 25

Replace Nested Conditional with

Guard Clauses

Use guard clauses for special cases:

double getPayAmount () { if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); return normalPayAmount(); }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 26

Replace Nested Conditional with

Guard Clauses

„ Motivation: clarify when ifs are testing for special

cases, versus situation where then/else are both

normal

„ Mechanics:

„ For each check, put in a guard clause

„ Should either return or throw an exception

„ Compile and test after each replacement

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 27

Replace Nested Conditional with

Guard Clauses: Example 1 - Start

double getPayAmount () { double result; if (_isDead) result = deadAmount(); else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; } return result; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 28

Replace Nested Conditional with Guard

Clauses: Example 1 – First guard

double getPayAmount () { double result; if (_isDead) return deadAmount(); else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; } return result; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 29

Replace Nested Conditional with Guard

Clauses: Example 1 – Second guard

double getPayAmount () { double result; if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; return result; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 30

Replace Nested Conditional with Guard

Clauses: Example 1 – Third guard

double getPayAmount () { double result; if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); else result = normalPayAmount(); return result; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 37

Replace Nested Conditional with Guard

Clauses: Example 2 – Explicit results

public double getAdjustedCapital () { // example requires reversing sense of conditionals double result = 0.0; if (_capital <= 0.0) return 0.0; if (intRate <= 0.0 || _duration <= 0)) return 0.0; result = (_income / _duration) * ADJ_FACTOR; return result; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 38

Replace Nested Conditional with Guard

Clauses: Example 2 – Remove temp

public double getAdjustedCapital () { // example requires reversing sense of conditionals double result = 0.0; if (_capital <= 0.0) return 0.0; if (intRate <= 0.0 || _duration <= 0)) return 0.0; return (_income / _duration) * ADJ_FACTOR; return result; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 39

Replace Nested Conditional with Guard

Clauses: Example 2 – End

public double getAdjustedCapital () { // example requires reversing sense of conditionals // Note: May want to combine tests into one conditional, // or separate into three conditionals if (_capital <= 0.0) return 0.0; if (intRate <= 0.0 || _duration <= 0)) return 0.0; return (_income / _duration) * ADJ_FACTOR; }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 40

Replace Conditional with Polymorphism

Skipping, since it’s already familiar …

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 41

Introduce Null Object

You have repeated checks for a null value. Replace the

null value with a null object (and use polymorphism)

if (customer == null) plan = BillingPlan.basic(); else plan = customer.getPlan();

Add a new NullCustomer class and use it:

Plan = customer.getPlan();

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 42

Introduce Null Object

„ Motivation: Eliminate many tests and conditional

code

„ Also makes NullPointerException less likely

„ But can hide the same logical condition

„ This sometimes making debugging slightly harder

„ Benefits outweight disadvantages

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 43

Introduce Null Object: Mechanics

„ Create a Null version subclass. Implement an isNull() method for the original and new class. The null object should be a singleton of the null class

„ Compile

„ Replace setting to Java null with the null object

„ Replace comparisons with null by isNull() calls

„ Compile and test

„ For each conditional, add a method to the Null class that overrides; compile

„ Remove the condition check; compile and test

„ Repeat until all conditionals removed

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 44

Introduce Null Object:

Example - Classes

class Site …

Customer _customer;

Customer getCustomer () { return _customer; }

class Customer …

public String getName () { … }

public BillingPlan getPlan () { … }

public PaymentHistory getHistory () { … }

class PaymentHistory …

int getWeeksDelinquentInLastYear () { … }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 45

Introduce Null Object:

Example – Code fragment - Start

Customer customer = site.getCustomer();

BillingPlan plan;

if (customer == null) plan = BillingPlan.basic();

else plan = customer.getPlan();

String customerName;

if (customer == null) customerName = “occupant”;

else customerName = customer.getName();

int weeksDelinquent;

if (customer == null) weeksDelinquent = 0;

else weeksDelinquent =

customer.getHistory().getWeeksDelinquentInLastYear();

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 46

Introduce Null Object:

Example – Adding NullCustomer

class Customer … public boolean isNull () { return false; } protected Customer () {} // needed by subclass … class NullCustomer extends Customer { @Override public boolean isNull () { return true; } } // optional: use Nullable interface interface Nullable { boolean isNull(); } // have Customer implement this interface

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 47

Introduce Null Object:

Example – A factory method is good …

class Customer …

static Customer newNull() { return new NullCustomer(); // or … set up to use singleton pattern } …

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 48

Introduce Null Object:

Example – Update a source of nulls …

class Site … Customer getCustomer () { return (customer == null)? Customer.newNull() : _customer; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 55

Introduce Null Object:

Example – … and simplify once more

Customer customer = site.getCustomer();

BillingPlan plan = customer.getPlan();

String customerName = customer.getName();

int weeksDelinquent =

customer.getHistory().getWeeksDelinquentInLastYear();

if (customer.isNull()) weeksDelinquent = 0;

else weeksDelinquent =

customer.getHistory().getWeeksDelinquentInLastYear();

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 56

Introduce Null Object:

Example – End

Customer customer = site.getCustomer();

BillingPlan plan = customer.getPlan();

String customerName = customer.getName();

int weeksDelinquent =

customer.getHistory().getWeeksDelinquentInLastYear();

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 57

Introduce Null Object: Comments

„ You may have several kinds of null object

„ NoCustomer vs. UnknownCustomer, for example

„ The null class gets the most common behavior

„ But specific cases can still use isNull if they are

different

„ More generally, may have several special case objects

„ This pattern tends to remove exceptions, replacing

with special case behavior in the null objects

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 58

Introduce Assertion

Code assumes something implicitly: make it explicit!

double getExpenseLimit () { // should have a limit or a primary project return (_expenseLimit != NULL_EXPENSE)? _expenseLimit : _primaryProject.getMemeberExpenseLimit(); }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 59

Introduce Assertion

With the explicit assertion:

double getExpenseLimit () { assert (_expenseLimit != NULL_EXPENSE) || (_primaryProject != null); return (_expenseLimit != NULL_EXPENSE)? _expenseLimit : _primaryProject.getMemeberExpenseLimit(); }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 60

Introduce Assertion

„ Use only for conditions that should never be false

according to the logic of the program

„ Use other exceptions for bad input, I/O failure, etc.

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 61

Recap of Simplifying Conditionals

„ Decompose Conditional

„ Consolidate Conditional Expressions

„ Consolidate Duplicate Conditional Fragments

„ Remove Control Flag

„ Replace Nested Conditional with Guard Clauses

„ Replace Conditional with Polymorphism

„ Introduce Null Object

„ Introduce Assertion

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 62

Making Method Calls Simpler

„ Many, perhaps most, of these are simple to apply

„ So we won’t belabor the easy ones

„ May seem trivial, so why are they important?

„ “Naming is a key tool in communication.”

„ Interfaces are key to good [OO] software

„ Being clear about mutating vs. non-mutating methods

„ Show what you have to, hide the rest

„ Use exceptions appropriately

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 63

Rename Method

„ Simple to do

„ Humans need good names

„ Compare getinvcdtlmt vs. getInvoiceableCreditLimit „ Choosing good names is a skill that you develop

„ The sort of thing that Eclipse automates

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 64

Add Parameter

„ Simple to do

„ The sort of thing that Eclipse automates

„ But beware; ask these questions:

„ Can an existing parameter get the info you need?

„ How about adding a method to an existing parameter?

„ Should the behavior be on a different object?

„ Perhaps you are creating a data clump, or should

consider Introduce Parameter Object?

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 65

Remove Parameter

„ Simple to do

„ The sort of thing that Eclipse automates

„ Generally good to do if parameter no longer used in

the method

„ But may be necessary in the case of an inherited

method

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 66

Separate Query from Modifier

„ Query = a method that reads but does not modify

„ Modifier = a method that modifies object state

„ Generally: if a method returns a value, it should not

modify state

„ If it does, try to separate the query from the modifier

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 73

Separate Query from Modifier

Example – … and change its name

void sendAlert (String[] people) {

for (String person : people) {

if (person.equals(“Don”)) {

sendAlert();

return;

if (person.equals(“John”)) {

sendAlert();

return;

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 74

Separate Query from Modifier

Example – … and apply Substitute Algorithm

void sendAlert (String[] people) { if (! foundPerson(people).equals(“”)) sendAlert(); }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 75

Parameterize Method

Before:

fivePercentRaise() {…}

tenPercentRaise() {…}

After:

raise(float percentage) {…}

This case is pretty obvious. Here is one that is more

subtle …

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 76

Parameterize Method – Subtle Example

Dollars baseCharge () { double result = Math.min(lastUsage(),100) * 0.03; if (lastUsage() > 100) { result += (Math.min(lastUsage(),200)-100)0.05; }; if (lastUsage() > 200) { result += (lastUsage() – 200) * 0.07; }; return new Dollars(result); }*

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 77

Parameterize Method – Subtle Example;

combines with Extract Method (implicitly)

Dollars baseCharge () {

double result = usageInRange(0, 100) * 0.03;

result += usageInRange(100, 200) * 0.05;

result += usageInRange(200, Integer.MAX_VALUE) * 0.07;

return new Dollars(result);

protected int usageInRange (int start, int end) {

if (lastUsage() > start)

return Math.Min(lastUsage(), end) – start;

else

return 0;

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 78

Replace Parameter with

Explicit Methods

void setValue (String name, int value) { if (name.equals(“height”)) { _height = value; return; } if (name.equals(“width”)) { _width = value; return; } assert false; } // change to new methods: void setHeight (int arg) { _height = arg; } void setWidth (int arg) { _width = arg; }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 79

Replace Parameter with

Explicit Methods - Motivation

„ Use when you do largely different things depending on the

parameter value, and the parameter value is usually a

constant

„ Caller has to supply the parameter anyway, so could just as

well call an explicit method (in most cases)

„ Clearer

„ Better compile-time checking

„ Possible parameter values explicit

„ Might consider using a setter, or Replace Conditional with

Polymorphism, in some cases

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 80

Replace Parameter with

Explicit Methods - Mechanics

„ Create a method for a leg; compile

„ Change callers for that case; compile; test

„ Repeat until all cases handled

„ Delete original method; compile; test

We skip showing it in detail since it is straightfoward

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 81

Preserve Whole Object

Before:

int low = daysTempRange().getLow ();

int high = daysTempRange().getHigh();

withinPlan = plan.withinRange(low, high);

After:

withinPlan = plan.withinRange(daysTempRange());

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 82

Preserve Whole Object - Motivation

„ Reduces changes to callers if called routine’s needs

change in the future

„ Downside: creates dependency on an object as

opposed to separate values

„ Consider also Move Method

„ May need to do Introduce Parameter Object first

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 83

Preserve Whole Object - Mechanics

„ Add a parameter for the whole object, to the parameter list

and to each call; compile; test

„ Replace uses of one parameter in called method to get value

from whole object; compile; test

„ Delete that parameter (from list and each call); compile; test

„ Repeat until no more parameters can be deleted

„ Delete code in called that obtains parameters (if possible);

compile; test

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 84

Preserve Whole Object

Example - Start

class Room … boolean withinPlan (HeatingPlan plan) { int low = daysTempRange().getLow(); int high = daysTempRange().getHigh(); return plan.withinRange(low, high); }

class HeatingPlan … private TempRange _range; boolean withinRange (int low, int high) { return (low >= _range.getLow() && high <= _range.getHigh()); }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 91

Preserve Whole Object

Example – End

class Room …

boolean withinPlan (HeatingPlan plan) {

return plan.withinRange(daysTempRange());

class HeatingPlan …

private TempRange _range;

boolean withinRange (TempRange roomRange) {

return (roomRange.getLow () >= _range.getLow () &&

roomRange.getHigh() <= _range.getHigh());

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 92

Preserve Whole Object

Example – Can apply Move Method

class HeatingPlan …

private TempRange _range;

boolean withinRange (TempRange roomRange) {

return (_range.includes(roomRange));

class TempRange …

boolean includes (TempRange arg) {

return (arg.getLow () >= this.getLow () &&

arg.getHigh() <= this.getHigh());

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 93

Replace Parameter with Method

Before:

int basePrice = _quantity * _itemPrice;

discountLevel = getDiscountLevel();

double finalPrice =

discountedPrice(basePrice, discountLevel);

After:

int basePrice = _quantity * _itemPrice;

double finalPrice = discountedPrice (basePrice);

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 94

Replace Parameter with Method –

When?

„ Invoke a method

„ And: pass its result back to another method

„ And: target of second call can call the first method

for itself

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 95

Replace Parameter with Method –

Motivation

„ If a method can get a value some other way, avoid

passing it as a parameter

„ If parameter is there for future flexibility, still

consider removing it and dealing with that later

„ Skip mechanics since it’s straightforward

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 96

Introduce Parameter Object

A group of parameters that naturally go together:

replace with an object.

Before:

amountInvoicedIn(Date start, Date end) { … }

amountReceivedIn(Date start, Date end) { … }

amountOverdueIn(Date start, Date end) { … }

After:

amountInvoicedIn(DateRange range) { … }

amountReceivedIn(DateRange range) { … }

amountOverdueIn(DateRange range) { … }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 97

Introduce Parameter Object -

Motivation

„ A data clump should be an object for clarity

„ Reduces size of parameter lists: also clearer

„ The accessors make the code more consistent

„ Often a prelude to moving behavior to the clump

„ Thus, often reduces duplication

„ Details similar to things previously shown, so we

skip them

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 98

Remove Setting Method

You have a field that should be set at creation time and never

altered: Remove any setting method for it

„ Motivation:

„ Makes intent clear „ Removes possibility of change

„ Mechanics

„ Mostly obvious, so we skip „ In a subclass, may need a setter in superclass for setting some private fields, but give it a name that makes clear it is not an ordinary setter

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 99

Hide Method

You have a method that is not used by any other class:

make it private

„ Motivation:

„ Keeps interface as narrow as possible

„ Tends to happen as classes evolve richer behavior

„ Mechanics

„ Obvious

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 100

Replace Constructor with Factory

Method

We studied factories early in the course.

The mechanics are straightforward.

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 101

Encapsulate Downcast

A method returns an object that callers will need to

downcast: Move the downcast inside the method

Before:

Object lastReading () {

return readings.lastElement();

After:

Reading lastReading () {

return (Reading)readings.lastElement();

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 102

Encapsulate Downcast

„ Motivation

„ Not as necessary when you use generics

„ But clone() is a good example that remains „ Recall that we put the downcast inside the memento() method

„ (We also put an exception handler there: same principle)

„ Make the object’s interface better typed

„ Mechanics: Straightforward

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 109

Replace Exception with Test

Example – Start

class ResourcePool …

private ArrayList _available = …;

Resource getResource () {

try {

return _available.remove(_available.size()-1);

} catch (IndexOutOfBoundsException e) {

return new Resource();

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 110

Replace Exception with Test

Example – With test for exceptional case

class ResourcePool …

private ArrayList _available = …;

Resource getResource () {

if (_available.isEmpty()) {

return new Resource();

try {

return _available.remove(_available.size()-1);

} catch (IndexOutOfBoundsException e) {

return new Resource();

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 111

Replace Exception with Test

Example – Add assertion (then test)

class ResourcePool … private ArrayList _available = …; Resource getResource () { if (_available.isEmpty()) { return new Resource(); }; try { return _available.remove(_available.size()-1); } catch (IndexOutOfBoundsException e) { assert false; return new Resource(); } }

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 112

Replace Exception with Test

Example – Remove try block

class ResourcePool … private ArrayList _available = …; Resource getResource () { if (_available.isEmpty()) { return new Resource(); }; try { return _available.remove(_available.size()-1); } catch (IndexOutOfBoundsException e) { assert false; return new Resource(); } }

UU NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERSTMHERST •• Department of Computer ScienceDepartment of Computer Science 113

Replace Exception with Test

Example – End

class ResourcePool …

private ArrayList _available = …;

Resource getResource () {

if (_available.isEmpty()) {

return new Resource();

return _available.remove(_available.size()-1);

U U NIVERSITY OFNIVERSITY OF MM ASSACHUSETTSASSACHUSETTS , A, A MHERST •MHERST• Department of Computer ScienceDepartment of Computer Science 114

Next time …

Continue expanding your catalog of refactorings …