1 / 54

Lesson Five: Conditionals

Lesson Five: Conditionals. Conditionals should not be too complex. If they are complex, refactor them to make simple methods making readability and understandability better. Learning objective – have simple conditionals which are self documenting with meaningful names.

jud
Download Presentation

Lesson Five: Conditionals

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lesson Five: Conditionals

  2. Conditionals should not be too complex. If they are complex, refactor them to make simple methods making readability and understandability better.

  3. Learning objective – have simple conditionals which are self documenting with meaningful names

  4. In our program with explaining variable names, there are still some conditionals which are difficult to understand. We find them in mainly in bestMove().

  5. FOR EXAMPLEint bestMove(int computerStatus, int userStatus) { …… if (((computerStatus & (1 << potentialComputerMove)) == 0) && ((userStatus & (1 << potentialComputerMove)) == 0)) if (((potentialComputerStatus & (1 << j)) == 0) && ((userStatus & (1 << j)) == 0)) if (((computerStatus & (1 <<firstAvailableComputerMove)) == 0) && ((userStatus & (1 <firstAvailableComputerMove)) == 0)) {

  6. REFACTORINGSDecomposing ConditionalConsolidating Conditional Statements Consolidate Duplicate Conditional FragmentsReplace Nested Conditional with Guard ClausesRemove Control Flag

  7. Decompose Conditional Summary: You have a complicated conditional (if-then-else) statement. Extract methods from the condition, then part, and else parts.

  8. Decompose Conditional: Motivation: Complexity exist in a heavy if then else structure and you want to make the code more readable and understandable. You extract methods and name them where the code is readable and make small boolean methods to make the logic more understandable.

  9. Decompose Conditional: if (date.before (SUMMER_START) || date.after(SUMMER_END)) charge – qualitity * _winterRate + _winterServiceCharge; else charge – quantity * _summerRate; if (notSummer_date)) charge = winterCharge(quantity); else charge = summerCharge (quantity); GOES TO

  10. Decompose Conditional: if (date.before (SUMMER)START) || date.after(SUMMER_END)) charge – qualitity * _winterRate + _winterServiceCharge; else charge – quantity * _summerRate; Consider the following initial if statement.

  11. Decompose Conditional: If(notSummer(date) charge = winterCharge(quantity); else charge = summerCharge (quantity); private boolean notSummer (Date date) { return date.before (SUMMER_START) || date.after (SUMMER_END); } // end not summer private double summerCharge (int quantity) { return quantity * _summerRate; } // end summercharge private double winterCharge (int quantity) { return quantity * _winterRate + )winterServiceCharge; } Extract the conditional and each leg as follows.

  12. Decompose Conditional: Mechanics: Extract the condition into its own method Extract the then part then the else part Compile and test

  13. Consolidate Conditional Expressions Summary: You have a sequence of conditional tests with the same result. Combine them into a single conditional expression and extract it.

  14. Consolidate Conditional Expressions: Motivation: Sometimes you have a series of conditional checks in which the conditional statements are different but the effects are the same.

  15. Consolidate Conditional Expressions: double disabilityAmount() { if (_seniority < 2) return 0; if (_monthsDisabled > 12) return 0; if (_isPartTime) return 0; // compute the disability amount Double diabilityAmount () { if (isNOtEligableForDisability ()) return 0; // computer the disability amount GOES TO.

  16. Consolidate Conditional Expressions: double disabilityAmount() { if (_seniority < 2) return 0; if (_monthsDisabled > 12) return 0; if (_isPartTime) return 0; // compute the disability amount double diabilityAmount () { if (_seniority < 2) || (_monthsDisabled > 12) || (_isPartTime)) return 0; // computer the disability amount Assume the following. These statements may be equivalent of a complex or statement

  17. Consolidate Conditional Expressions: double disabilityAmount() { if (isEligibleForDiability()) return 0; // computer the disability amount Boolean isEligibleForDisability() { return ((_seniority < 2) || (_monthsDisabled > 12) || (_isPartTime)); } // end is ElibibleFor Disability Look at the condition and use extract method to communicate what the condition is looking for.

  18. Consolidate Conditional Expressions: if (onVacation()) if (lengthOfService*( > 10 ) return 1; return 0.5; if (onVacation () && lengthOfService () > 10) return 1; else return 0.5; This can be done with ands.

  19. Consolidate Conditional Expressions: if (onVacation() && lengthOfService*( > 10 ) return 1; return 0.5; return (onVacation () && lengthOfService () > 10) ? 1: 0.5; Given the following Test only the condition and returns a value turn the routine into a single return statements using the ternary operator.

  20. Consolidate Conditional Expressions: Mechanics: Check that none of the conditional has side effects. Replace the string of conditionals with a single conditional statement using logical operators. Compile and test. Consider using Extract Method on the condition.

  21. Consolidate Duplicate Conditional Fragments Summary: The same fragment of code is in all branches of a conditional expression. Move it outside of the expression.

  22. Consolidate Duplicate Conditional Fragments: Motivation: Sometime you find the same code executed in all legs of a conditional. This requires you move the code outside the conditional to make it more clear what remains constant.

  23. Consolidate Duplicate Conditional Fragments: if (isSpecialDeal() ) { total = price * 0.95; send (); } // end if else { total – price * 0.98; send(); } // end else if (isSpecialDeal() ) total = price * 0.95; else total =price * 0.98; send(); You begin with the following Move the send method out since it is used by both

  24. Consolidate Duplicate Conditional Fragments: Mechanics: Identify code that is executed. If common code is at the beginning, do it before conditional. If the code is at the end, move it after the conditional If the common code is in the middle, see if you can move it forward or backward. If there is more than one line of code extract method.

  25. Remove Control Flag Summary: You have a variable that is acting as a control flag for a series of boolean expressions. Use a break or return instead.

  26. Remove Control Flag: Motivation: You have a control flag that allows exit from the conditional statements. These control flags add complexity. Get rid of the control flag.

  27. Remove Control Flag: void checkSecurity (String [ ] people) { boolean found = false; for (int i = 0; i < people.length; i++) { if (!found) { // this is the flag if (people[i].equals (“Don”)) { sendAlert(); found = true; } if (people[i].equals (“John”)) { sendAlert(); found = true; } } // end if } // end for } // end checkSecurity Function checks a people list for suspicious characters

  28. Remove Control Flag: void checkSecurity (String [ ] people) { boolean found = false; for (int i = 0; i < people.length; i++) { if (!found) { if (people[i].equals (“Don”)) { sendAlert(); found = true; break; } if (people[i].equals (“John”)) { sendAlert(); found = true; break; } } // end if } // end for } // end checkSecurity The control flag is the piece that sets the found variable. Step 1: Set breaks in one at a time. Leave in flag.

  29. Remove Control Flag: void checkSecurity (String [ ] people) { for (int i = 0; i < people.length; i++) { if (people[i].equals (“Don”)) { sendAlert(); break; } if (people[i].equals (“John”)) { sendAlert(); break; } } // end for } // end checkSecurity Step 2: Remove control flag references.

  30. Remove Control Flag: String checkSecurity (String [ ] people) { for (int i = 0; i < people.length; i++) { if (people[i].equals (“Don”)) { sendAlert(); return “Don”; } if (people[i].equals (“John”)) { sendAlert(); return “John”; } } // end for return “”; // returns null if neither } // end checkSecurity You can use the return statement with function returning a String.

  31. Remove Control Flag: Mechanics: Find the value of the control flag that gets you out of the logic statement. Replace assignments of the break-out value with a break or continue statement. Compile and test after each replacement.

  32. Replace Nested Conditional with Guard Clauses Summary: A method has conditional behavior that does not make clear the normal path of execution. Use guard clauses for all the special cases.

  33. Replace Nested Conditional with Guard Clauses: Motivation: Expressional statement may be of two forms, One form is whether either course is part of the normal behavior And the second form is a situation in which one answer from the conditional indicates normal behavior and the other indicates an unusual condition.

  34. Replace Nested Conditional with Guard Clauses: Motivation: (con’t) Each type of conditions have different intensions. If both are part of normal behavior, use a condition with an if and an else leg. If the condition is a unusual condition, check the condition and return if the condition is true. This is called a guard clause.

  35. Replace Nested Conditional with Guard Clauses: double getPayAmount() { double result; if (_isDead) result = deathAmount(); // this is NOT a normal course else { if (_isSeparated) result = separatedAmount(); // this is a normal course else { if (_isRetired) result = retiredAmount(); // this is a normal course else result = normalPayAmount(); // this is the normal course } // end else } // end else return result } // end getPayAmount Given

  36. Replace Nested Conditional with Guard Clauses: double getPayAmount() { if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); return normalPayAmount(); } // end getPayAmount GOES TO separating out the behaviors.

  37. 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(); } // end else } // end else return result } // end getPayAmount Given this initial code as shown before -- this is not unlikely code

  38. Replace Nested Conditional with Guard Clauses: double getPayAmount() { double result; if (_isDead) return deadAmount(); // this is masking of normals else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); } // end else } // end else return result } // end getPayAmount Checking masking the normal course of action behind the checking. So we use a guard clause one at a time.

  39. Replace Nested Conditional with Guard Clauses: Mechanics: For each check put in the guard clause. Compile and test after each check is replaced with a guard clause.

  40. Replace Conditional with Polymorphism Summary: 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.

  41. Replace Conditional with Polymorphism: Motivation: Avoid writing explicit conditional statements when you have objects whose behavior varies depending on the type of object you are dealing with. Polymorphism gives you the advantage.

  42. Replace Conditional with Polymorphism: double getSpeed() { switch ()type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() – getLoadFactor() * _numberOfCoconuts; case NORWEGIAN_BLUE: return (_isNailed) ? 0 ; getBaseSpeed (_voltage); } // end switch throw new RuntimeException (“Should be unreachable”); } // end getSpeed Given the following speeds for different types of birds

  43. Replace Conditional with Polymorphism: GOES TO Bird ____________ getSpeed Bird ____________ getSpeed Bird ____________ getSpeed Bird ____________ getSpeed

  44. Replace Conditional with Polymorphism: Method: 1. Use Extract Method to take apart the conditional. 2. Use either Replace Type Code with SubClasses OR Use Replace Type Code with State/Strategy 3. Use Move Method to place condition in an isa structure. 4. Create sub-classes with overriding methods.

  45. Replace Conditional with Polymorphism: Suppose you have the following inheritance structure Employee Employee Type ENGINEER SALESMAN MANAGER

  46. Replace Conditional with Polymorphism: class Employee.. int payAmount() { switch (getType)() { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + commission; case EmployeeType.MANAGER: return _monthlySalary + bonus; default; throw new RuntimeException (“Incorrect Employee”); } // end switch } // end Employee With the following code

  47. Replace Conditional with Polymorphism: int getType () { return _type.getTypeCode(); } // returns type of object private EmployeeType _type; // an instance of employee type in the program abstract class EmployeeType…. // is the abstract class of employee type abstract int getTypeCode(); class Engineer extends EmployeeType… // defines the subclass int getTypeCode() { return Employee.ENGINEER; } // this returns the type With the following code

  48. Replace Conditional with Polymorphism: class EmployeeType… // this code used to be in Employee int payAmount (Employee emp) { switch (getTypeCode ()) { case ENGINEER: return emp.getMonthlySalary (); case SALESMAN: return emp.getMonthlySalary () + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException (“Incorrect Employee”); The case statement is extracted so I move it into employee type.

  49. Replace Conditional with Polymorphism: class Employee… int payAmount () { return _type.payAmount (this)) class Engineer… int payAmount (Employee emp) { return emp.getMonthlySalary(); } Change the payAmount method to delegate to the new class. Work on Case statement – copy engineer leg to engineer class

  50. Replace Conditional with Polymorphism: class EmployeeType… int payAmount (Employee emp) { switch (getTypeCode ()) { case ENGINEER: throw new RuntimeException (“Should be being overridden”); case SALESMAN: return emp.getMonthlySalary () + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException (“Incorrect Employee”); The new method overrides the case statement for engineers I can place a trap here to make sure I made no mistakes

More Related