Refactoring Conditionals Lesson Five: Conditionals.

Slides:



Advertisements
Similar presentations
Module 7. Simplifying Conditional Expressions Course: Refactoring.
Advertisements

Software Testing and Maintenance 1 Today’s Agenda  Course Evaluation  HW 4 Return  HW 5 Correction  Quiz 4 Next Class  Software Refactoring.
Refactoring and Code Smells
Intro to OOP with Java, C. Thomas Wu Inheritance and Polymorphism
Software Engineering Key Refactorings
C++ Programming: From Problem Analysis to Program Design, Third Edition Chapter 4: Control Structures I (Selection)
Introduction to Refactoring Excerpted from ‘What is Refactoring?’ by William C. Wake and Refactoring: Improving the Design of Existing Code by Martin Fowler.
George Blank University Lecturer. REFACTORING Improving the Design of Existing Code Supplement to Ian Sommerville, Software Engineering, Chapter 20 Prepared.
REFACTORING Improving the Design of Existing Code Atakan Şimşek e
C++ for Engineers and Scientists Third Edition
Maintenance Refactoring and Code Smells. Where are we? Over the semester we have talked about Software Engineering. The overall goal of software engineering.
(c) University of Washington04-1 CSC 143 Java Inheritance Example (Review)
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
Programming Logic and Design Sixth Edition
Advanced Programing practices
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
Chapter 3 Making Decisions
CPS120: Introduction to Computer Science Decision Making in Programs.
Chapter 6: Code Refactoring Omar Meqdadi SE 3860 Lecture 6 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.
Refactoring. Mathematics: Factor ● fac·tor – One of two or more quantities that divides a given quantity without a remainder, e.g., 2 and 3 are factors.
Refactoring Improving the structure of existing code Refactoring1.
Refactoring1 Refactoring DEPARTMENT OF COMPUTER SCIENCE AND SOFTWARE ENGINEERING CONCORDIA UNIVERSITY February 6, 2009.
SWE 316: Software Design and Architecture Objectives Lecture # 20 Improving the existing design: Refactoring SWE 316: Software Design and Architecture.
Variables and Functions. Open your Encoder program Let’s begin by opening the “Labyrinth Auto Straight” code. Save this file as Labyrinth with variables.
1 Software Maintenance and Evolution CSSE 575: Session 3, Part 1 Simplifying Conditionals Steve Chenoweth Office Phone: (812) Cell: (937)
CPS120: Introduction to Computer Science Decision Making in Programs.
Refactoring Deciding what to make a superclass or interface is difficult. Some of these refactorings are helpful. Some research items include Inheritance.
Refactoring 2. Admin Blackboard Quiz Acknowledgements Material in this presentation was drawn from Martin Fowler, Refactoring: Improving the Design of.
REFACTORINGREFACTORING. Realities Code evolves substantially during development Requirements changes 1%-4% per month on a project Current methodologies.
NJIT 1 Test Driven Development and Refactoring Larman, Chapter 21.
Chapter 5: Making Decisions. Objectives Plan decision-making logic Make decisions with the if and if…else structures Use multiple statements in if and.
COP3502 Programming Fundamentals for CIS Majors 1 Instructor: Parisa Rashidi.
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
SEG 4110 – Advanced Software Design and Reengineering Topic T Introduction to Refactoring.
Refactoring Advanced Software Engineering Dr Nuha El-Khalili.
Refactoring. Mathematics: Factor ● fac·tor – One of two or more quantities that divides a given quantity without a remainder, e.g., 2 and 3 are factors.
CSSE 375 Organizing Data – Part 2 Shawn and Steve Continue the same quiz!
Refactoring. 2 Process of changing a software system in such a way that it does not alter the external behavior of the code, yet improves its internal.
An Object-Oriented Approach to Programming Logic and Design Chapter 5 Making Decisions.
Software Construction and Evolution - CSSE 375 Simplifying Conditionals Shawn & Steve.
Refactoring Constants and Variables Lesson Three: Constants and Variables.
CSSE 375 Organizing Data – Part 1 Shawn and Steve Q1.
REFACTORING CHANGE VALUE TO REFERENCE SUBSTITUTE ALGORITHM REPLACE CONDITIONAL WITH POLYMORHPISM.
CPS120: Introduction to Computer Science Decision Making in Programs.
Refactoring. DCS – SWC 2 Refactoring ”A change made to the internal structure of software to make it easier to understand and cheaper to modify without.
Module 9. Dealing with Generalization Course: Refactoring.
Chapter 9: Continuing Classes By Matt Hirsch. Table Of Contents 1.Static Fields and Methods 2.Inheritance I. Recycle Code with Inheritance II. Overriding.
Catalog of Refactoring (5) Simplifying Conditional Expressions.
C++ Programming: From Problem Analysis to Program Design, Fifth Edition Chapter 2: Control Structures (Selection & Repetition)
Code Refactoring Milan Vukoje Soprex SkfOffice2 SkfOffice3 Big5 Quality oriented We are hiring…
Catalog of Refactoring (1) Composing Methods. Code Smells Long methods Dubious temporary variables Dubious methods.
Programming Logic and Design Fifth Edition, Comprehensive Chapter 4 Making Decisions.
C++ for Engineers and Scientists Second Edition Chapter 4 Selection Structures.
Catalog of Refactoring (6) Making Method Calls Simpler.
Control Structures- Decisions. Smart Computers Computer programs can be written to make computers seem smart Making computers smart is based on decision.
Refactoring (1). Software Evolution Cope with change Feature bloat Design decay Code duplications “Pattern time is refactoring time” Make future changes.
Module Road Map Refactoring Why Refactoring? Examples
Inheritance and Polymorphism
EGR 2261 Unit 4 Control Structures I: Selection
Control Statements Lecture 6 from Chapter 5.
Refactoring and Code Smells
SWEN-610 Foundations of Software Engineering
Refactoring and Code Smells
Chapter 6 Control Statements: Part 2
Refactoring Strategies
Refactoring and Code Smells
Advanced Programing practices
Refactoring and Code Smells
Controlling Program Flow
Refactoring and Code Smells
Presentation transcript:

Refactoring Conditionals Lesson Five: Conditionals

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

Refactoring Conditionals Learning objective – have simple conditionals which are self documenting with meaningful names

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

Refactoring Conditionals FOR EXAMPLE int 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)) {

Refactoring Conditionals REFACTORINGS Decomposing Conditional Consolidating Conditional Statements Consolidate Duplicate Conditional Fragments Replace Nested Conditional with Guard Clauses Remove Control Flag

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

Refactoring Conditionals 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.

Refactoring Conditionals 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

Refactoring Conditionals 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.

Refactoring Conditionals 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.

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

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

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals 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 12) || (_isPartTime)) return 0; // computer the disability amount Assume the following. These statements may be equivalent of a complex or statement

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

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals 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.

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

Refactoring Conditionals 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.

Refactoring Conditionals 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

Refactoring Conditionals 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.

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

Refactoring Conditionals 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.

Refactoring Conditionals 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

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals Summary: 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

Refactoring Conditionals 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.

Refactoring Conditionals 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.

Refactoring Conditionals 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 return result } // end getPayAmount Given

Refactoring Conditionals 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.

Refactoring Conditionals 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 return result } // end getPayAmount Given this initial code as shown before -- this is not unlikely code

Refactoring Conditionals 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 return result } // end getPayAmount Checking masking the normal course of action behind the checking. So we use a guard clause one at a time.

Refactoring Conditionals 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.

Refactoring Conditionals 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. Replace Conditional with Polymorphism

Refactoring Conditionals 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.

Refactoring Conditionals 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

Refactoring Conditionals Replace Conditional with Polymorphism: GOES TO Bird ____________ getSpeed Bird ____________ getSpeed Bird ____________ getSpeed Bird ____________ getSpeed

Refactoring Conditionals 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.

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

Refactoring Conditionals 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

Refactoring Conditionals 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

Refactoring Conditionals 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.

Refactoring Conditionals 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

Refactoring Conditionals 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

Refactoring Conditionals Replace Conditional with Polymorphism: class Employee… int payAmount () { return _type.payAmount (this)) class Engineer… int payAmount (Employee emp) { return emp.getMonthlySalary(); } I can then replace this switch statement entirely With a polymorphic call.

Refactoring Conditionals Replace Conditional with Polymorphism: Mechanics: If the conditional statement is one part of a larger method, take apart the conditional statement and use Extract Method. If necessary use Move method to place the conditional at the top of the inheritance structure. Pick one of the subclasses. Remove the copied leg of the conditional statement. Compile and test.

Refactoring Conditionals if (((computerStatus & (1 << firstAvailableComputerMove)) == 0) && ((userStatus & (1 << firstAvailableComputerMove)) == 0)) public boolean cellEmpty (int computerStatus,int potentialComputerMove,int userStatus) { return ((computerStatus & (1 << potentialComputerMove)) == 0) && ((userStatus & (1 << potentialComputerMove)) == 0); } // end cellEmpty BECOMES

Refactoring Conditionals if ((getComputerStatus() & (1 << i)) != 0) public boolean squareOccupied (int i, int playerStatus) { return ((playerStatus & (1 << i)) != 0); } // end squareOccupied BECOMES WITH if (squareOccupied (i, getComputerStatus())) REUSED 3 times