Module 7. Simplifying Conditional Expressions Course: Refactoring.

35
Module 7. Simplifying Conditional Expressions Course: Refactoring

Transcript of Module 7. Simplifying Conditional Expressions Course: Refactoring.

Page 1: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Module 7. Simplifying Conditional Expressions

Course: Refactoring

Page 2: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Overview

Decompose Conditional

Consolidate Conditional Expression

Consolidate Duplicate Conditional Fragments

Remove Control Flag

Replace Nested Conditional with Guard Clauses

Replace Conditional with Polymorphism

Introduce Null Object

Introduce Assertion

Page 3: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Decompose Conditional

You have a complicated conditional (if-then-else) statement.

Extract methods from the condition, then part, and else parts.

Page 4: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Decompose Conditional

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

charge = quantity * _winterRate + _winterServiceCharge;

else

charge = quantity * _summerRate;

if (notSummer(date))

charge = winterCharge(quantity);

else

charge = summerCharge (quantity);

Page 5: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Decompose Conditional

Before:

complexity in a program lies in complex conditional logic a pretty long method

After:

make your intention clearer by decomposing doing this for

the conditional part

each of the alternatives highlight the reason for the branching

Page 6: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Decompose Conditional: Mechanism

Extract the condition into its own method.

Extract the then part and the else part into their own methods.

Page 7: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Conditional Expression

You have a sequence of conditional tests with the same result.

Combine them into a single conditional expression and extract it.

Page 8: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Conditional Expression

double disabilityAmount() {

if (_seniority < 2) return 0;

if (_monthsDisabled > 12) return 0;

if (_isPartTime) return 0;

// compute the disability amount

double disabilityAmount() {

if (isNotEligableForDisability()) return 0;

// compute the disability amount

Page 9: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Conditional Expression

Before:

a series of conditional checks with the same result

After:

it makes the check clearer sets you up for Extract Method

Hit:

code already communicates your intention

Page 10: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Conditional Expression: Mechanism

Check side effects.

A single conditional statement.

Compile and test.

Extract Method.

Page 11: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Duplicate Conditional Fragments

The same fragment of code is in all branches of a conditional expression.

Move it outside of the expression.

Page 12: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Duplicate Conditional Fragments

if (isSpecialDeal()) {

total = price * 0.95;

send();

}

else {

total = price * 0.98;

send();

}

if (isSpecialDeal())

total = price * 0.95;

else

total = price * 0.98;

send();

Page 13: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Consolidate Duplicate Conditional Fragments

Identify code.

Move it to before the conditional.

Move it to after the conditional.

Look code in the middle.

Extract that code into a method.

Page 14: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Remove Control Flag

You have a variable that is acting as a control flag for a series of boolean expressions.

Use a break or return instead.

done = false

while not done

if (condition)

do something

done = true

next step of loop

Page 15: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Remove Control Flag

Before:

more trouble rules of structured programming “one entry and one exit point”

After:

more exit point the conditional becomes so much more clear

Page 16: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Remove Control Flag: Mechanism

Find the value of the control flag.

A break or continue statement.

Compile and test.

Extract the logic into a method.

Find the value of the control flag.

Replace with a return.

Compile and test.

Return is better than break and continue

Control Flag vs Result value

Page 17: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Exercise

Remove Control Flag

Decompose Conditional else statements that are a double negative are

difficult to understand.

Page 18: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Replace Nested Conditional with Guard Clauses

A method has conditional behavior that does not make clear the normal path of execution.

Use guard clauses for all the special cases.

Page 19: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Replace Nested Conditional with Guard Clauses

double getPayAmount() {

double result;

if (_isDead) result = deadAmount();

else {

if (_isSeparated) result = separatedAmount();

else { if (_isRetired) result = retiredAmount();

else result = normalPayAmount(); };

}

return result; };

double getPayAmount() {

if (_isDead) return deadAmount();

if (_isSeparated) return separatedAmount();

if (_isRetired) return retiredAmount();

return normalPayAmount();

};

Page 20: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Replace Nested Conditional with Guard Clauses

Before:

conditional expressions come in two formstwo part of the normal behavior normal behavior

unusual condition

After:

use guard clause [Beck] and return the key point about is one of emphasis if-then-else construct you are giving equal weight

Hint:

clarity is the key principle: if the method is clearer with one exit point, use one exit point; otherwise don't.

Page 21: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Replace Nested Conditional with Guard Clauses

For each check put in the guard clause.

Compile and test.

Expressions.

Page 22: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Exercise

Replace Nested Conditional with Guard Clauses

Reversing the Conditions

Page 23: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Replace Conditional with Polymorphism

You have a conditional that chooses different behavior depending on the type of an object.

Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.

Page 24: Module 7. Simplifying Conditional Expressions Course: Refactoring.

double getSpeed() {

switch (_type) {

case EUROPEAN:

return getBaseSpeed();

case AFRICAN:

return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;

case NORWEGIAN_BLUE:

return (_isNailed) ? 0 : getBaseSpeed(_voltage);

}

throw new RuntimeException ("Should be unreachable");

}

Replace Conditional with Polymorphism

Page 25: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Before:

difficult to add a new type high coupling

After:

use polymorphism

switch or if-then-else are much less common just create a new subclass for a new condition reduces the dependencies

Replace Conditional with Polymorphism

Page 26: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Null Object

You have repeated checks for a null value.

Replace the null value with a null object.

Page 27: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Null Object

if (customer == null)

plan = BillingPlan.basic();

else

plan = customer.getPlan();

Page 28: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Null Object

Before: ask object for what type it is invoking some behavior based on the answer got rid of huge amounts of procedural code

After: object does the right thing

Use: the missing Gemstone session use of null object is the missing bin things almost never blow up use Singleton pattern

Page 29: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Null Object

1. Create a subclass with isNull operation.

2. Compile.

3. Find all places and replace.

4. Change null with isNull.

5. Compile and test.

6. Look for if not null.

7. Override the operation.

8. Remove the condition check

9. Compile, and test.

Page 30: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Assertion

A section of code assumes something about the state of the program.

Make the assumption explicit with an assertion.

Page 31: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Assertion

double getExpenseLimit() {

// should have either expense limit or a primary project

return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit : _primaryProject.getMemberExpenseLimit();

}

double getExpenseLimit() {

Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ?

_expenseLimit:

_primaryProject.getMemberExpenseLimit();

}

Page 32: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Assertion

Before :

assumptions can only be decoded by looking through an algorithm

After:

failure of an assertion indicates error should never be used by other usually are removed for production code important to signal something is an assertion communication and debugging aids help the reader understand the assumptions help catch bugs closer to their origin

Page 33: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Introduce Assertion: Mechanism

When you see that a condition is assumed to be true, add an assertion to state it.

Page 34: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Exercise

Null Object

Real Project

Page 35: Module 7. Simplifying Conditional Expressions Course: Refactoring.

Review

Decompose Conditional

Consolidate Conditional Expression

Consolidate Duplicate Conditional Fragments

Remove Control Flag

Replace Nested Conditional with Guard Clauses

Replace Conditional with Polymorphism

Introduce Null Object

Introduce Assertion