# Module 7. Simplifying Conditional Expressions Course: Refactoring.

## Presentation on theme: "Module 7. Simplifying Conditional Expressions Course: Refactoring."— Presentation transcript:

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 forms two 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

1. Use Extract Method. 2. Use Move Method. 3. Pick one of the subclasses. 4. Compile and test. 5. Remove the copied leg. 6. Compile and test. 7. Repeat with each leg. 8. Make the superclass method abstract.

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