Module 7. Simplifying Conditional Expressions Course: Refactoring.

Post on 14-Dec-2015

234 views 0 download

Tags:

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

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

Decompose Conditional

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

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

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);

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

Decompose Conditional: Mechanism

Extract the condition into its own method.

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

Consolidate Conditional Expression

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

Combine them into a single conditional expression and extract it.

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

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

Consolidate Conditional Expression: Mechanism

Check side effects.

A single conditional statement.

Compile and test.

Extract Method.

Consolidate Duplicate Conditional Fragments

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

Move it outside of the expression.

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();

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.

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

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

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

Exercise

Remove Control Flag

Decompose Conditional else statements that are a double negative are

difficult to understand.

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.

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();

};

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.

Replace Nested Conditional with Guard Clauses

For each check put in the guard clause.

Compile and test.

Expressions.

Exercise

Replace Nested Conditional with Guard Clauses

Reversing the Conditions

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.

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

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

Introduce Null Object

You have repeated checks for a null value.

Replace the null value with a null object.

Introduce Null Object

if (customer == null)

plan = BillingPlan.basic();

else

plan = customer.getPlan();

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

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.

Introduce Assertion

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

Make the assumption explicit with an assertion.

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();

}

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

Introduce Assertion: Mechanism

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

Exercise

Null Object

Real Project

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