Catalog of Refactoring (6) Making Method Calls Simpler.

Slides:



Advertisements
Similar presentations
The Line Class Suppose you are involved in the development of a large mathematical application, and this application needs an object to represent a Line.
Advertisements

METHOD OVERRIDING 1.Sub class can override the methods defined by the super class. 2.Overridden Methods in the sub classes should have same name, same.
Written by: Dr. JJ Shepherd
1 Software Maintenance and Evolution CSSE 575: Session 2, Part 2 Composing Methods Steve Chenoweth Office Phone: (812) Cell: (937)
Road Map Introduction to object oriented programming. Classes
CSM-Java Programming-I Spring,2005 Class Design Lesson - 4.
Terms and Rules Professor Evan Korth New York University (All rights reserved)
Chapter 10 Classes Continued
OOP Languages: Java vs C++
JUnit The framework. Goal of the presentation showing the design and construction of JUnit, a piece of software with proven value.
Programming Languages and Paradigms Object-Oriented Programming.
CSM-Java Programming-I Spring,2005 Introduction to Objects and Classes Lesson - 1.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
1 v1.6 08/02/2006 Overview of Eclipse Lectures 1.Overview 2.Installing and Running 3.Building and Running Java Classes 4.Refactoring 5.Debugging 6.Testing.
Introduction to Java Prepared by: Ahmed Hefny. Outline Classes Access Levels Member Initialization Inheritance and Polymorphism Interfaces Inner Classes.
Programming Languages and Paradigms Object-Oriented Programming (Part II)
The Java Programming Language
Refactoring Improving the structure of existing code Refactoring1.
SWE 316: Software Design and Architecture Objectives Lecture # 20 Improving the existing design: Refactoring SWE 316: Software Design and Architecture.
Refactoring1 Improving the structure of existing code.
Refactoring Deciding what to make a superclass or interface is difficult. Some of these refactorings are helpful. Some research items include Inheritance.
Design Patterns Gang Qian Department of Computer Science University of Central Oklahoma.
1 CSC/ECE 517 Fall 2010 Lec. 3 Overview of Eclipse Lectures Lecture 2 “Lecture 0” Lecture 3 1.Overview 2.Installing and Running 3.Building and Running.
Today’s Agenda  More refactoring patterns Software Testing and Maintenance 1.
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.
Rina System development with Java Instructors: Rina Zviel-Girshin Lecture 4.
Software Construction and Evolution - CSSE 375 Making Method Calls Simpler Shawn and Steve Below – “Be the character!” The late acting teacher Lee Strasberg.
1 Software Maintenance and Evolution CSSE 575: Session 3, Part 3 Dealing with Generalization Steve Chenoweth Office Phone: (812) Cell: (937)
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
CSSE 375 Organizing Data – Part 2 Shawn and Steve Continue the same quiz!
Refactoring1 Improving the structure of existing code.
Topic 8Classes, Objects and Methods 1 Topic 8 l Class and Method Definitions l Information Hiding and Encapsulation l Objects and Reference Classes, Objects,
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Written by: Dr. JJ Shepherd
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.
Software Construction and Evolution - CSSE 375 Dealing with Generalization Steve and Shawn Left – In the 1990 movie “The Freshman,” Matthew Broderick,
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.
5.1 Basics of defining and using classes A review of class and object definitions A class is a template or blueprint for an object A class defines.
Module 9. Dealing with Generalization Course: Refactoring.
Refactoring Refactoring plays a major role in the decisions of where to put responsibilities. While deciding where these responsibilities lie, a refactoring.
Catalog of Refactoring (3) Organizing Data. Catalog Self Encapsulate Field Replace Data Value with Object Change Value to Reference Change Reference to.
Catalog of Refactoring (5) Simplifying Conditional Expressions.
Catalog of Refactoring (1) Composing Methods. Code Smells Long methods Dubious temporary variables Dubious methods.
Classes CS 162 (Summer 2009). Parts of a Class Instance Fields Methods.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
ENCAPSULATION. WHY ENCAPSULATE? So far, the objects we have designed have all of their methods and variables visible to any part of the program that has.
Object Oriented Programming. Constructors  Constructors are like special methods that are called implicitly as soon as an object is instantiated (i.e.
Principles and examples
Catalog of Refactoring
Catalog of Refactoring
Lecture 3 John Woodward.
Module Road Map Refactoring Why Refactoring? Examples
Low Budget Productions, LLC
Inheritance and Polymorphism
Methods Attributes Method Modifiers ‘static’
Refactoring Methods: Kevin Murphy.
University of Central Florida COP 3330 Object Oriented Programming
Refactorings Luke Marsh.
Overview of Eclipse Lectures
Extending Classes.
Java Programming Language
//code refactoring Rename Method Introduce Assertion
Improving the structure of existing code
CS 112 Programming 2 Lecture 02 Abstract Classes & Interfaces (2)
Refactoring.
Presentation transcript:

Catalog of Refactoring (6) Making Method Calls Simpler

Catalog Rename Method Add/Remove Parameter Preserve Whole Object Introduce Parameter Object Replace Parameter with Method Replace Parameter with Explicit Methods Parameterize Method Separate Query from Modifier Hide Method Remove Setting Method Replace Constructor with Factory Method Encapsulate Downcast Replace Error Code with Exception Replace Exception with Test

Rename Method The name of a method does not reveal its purpose. Change the name of the method.

Mechanics 1.Check to see whether the method signature is implemented by a superclass or subclass. 2.Declare a new method with the new name. Copy the old body of code over to the new name and make any alterations to fit 3.Change the body of the old method so that it calls the new one 4.Find all references to the old method name and change them to refer to the new one. 5.Compile and test after each change. 6.Remove the old method If the old method is part of the interface and you cannot remove it, leave it in place and mark it as deprecated

Add Parameter A method needs more information from its caller. Add a parameter for an object that can pass on this information. Same mechanics as Rename Method

Remove Parameter A parameter is no longer used by the method body. Remove it. Same mechanics as Rename Method

Separate Query from Modifier You have a method that returns a value but also changes the state of an object. Create two methods, one for the query and one for the modification.

Motivation It is a good idea to clearly signal the difference between methods with observable side effects and those without –Reference transparency

Mechanism 1.Create a query method that returns the same value as the original method. 2.Modify the original method so that it returns the result of a call to the query. E.g. every return in the original method should say return newQuery() 3.For each call, replace the single call to the original method with a call to the query. Add a call to the original method before the line that calls the query 4.Make the original method have a void return type and remove the return expressions 5.Compile and test.

Example String foundMiscreant(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"; } return ""; } void checkSecurity(String[] people) { String found = foundMiscreant(people); someLaterCode(found); }

Example String foundPerson(String[] people){ for (int i = 0; i < people.length; i++) { if (people[i].equals ("Don")){ return "Don"; } if (people[i].equals ("John")){ return "John"; } return ""; } void sendAlert(found){ if (! found.equals("")) sendAlert(); } void checkSecurity(String[] people) { String found = foundPerson(people); sendAlert(found); someLaterCode(found); }

Parameterize Method Several methods do similar things but with different values contained in the method body. Create one method that uses a parameter for the different values.

Mechanics 1.Create a parameterized method that can be substituted for each repetitive method. 2.Replace one old method with a call to the new method 3.Repeat for all the methods 4.Compile and test after each change.

Example class Employee { void tenPercentRaise () { salary *= 1.1; } void fivePercentRaise () { salary *= 1.05; } void raise (double factor) { salary *= (1 + factor); }

Example protected Dollars baseCharge() { double result = Math.min(lastUsage(),100) * 0.03; if (lastUsage() > 100) { result += (Math.min (lastUsage(),200) - 100) * 0.05; }; if (lastUsage() > 200) { result += (lastUsage() - 200) * 0.07; }; return new Dollars (result); } protected Dollars baseCharge() { double result = usageInRange(0, 100) * 0.03; result += usageInRange (100,200) * 0.05; result += usageInRange (200, Integer.MAX_VALUE) * 0.07; return new Dollars (result); } protected int usageInRange(int start, int end) { if (lastUsage() > start) return Math.min(lastUsage(),end) - start; else return 0; }

Replace Parameter with Explicit Methods You have a method that runs different code depending on the values of an enumerated parameter. Create a separate method for each value of the parameter. Reverse of Parameterize Method

Motivation The caller has to decide what it wants to do by setting the parameter, so you might as well provide different methods and avoid the conditional Not only avoid the conditional behavior but also gain compile time checking Interface is clearer –No need to determine a valid parameter value, often poorly documented

Mechanism 1.Create an explicit method for each value of the parameter. 2.For each leg of the conditional, call the appropriate new method 3.Replace each caller of the conditional method with a call to the appropriate new method. 4.When all callers are changed, remove the conditional method 5.Compile and test every step.

Example static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; static Employee create(int type) { switch (type) { case ENGINEER: return new Engineer(); case SALESMAN: return new Salesman(); case MANAGER: return new Manager(); default: throw new IllegalArgumentException("Incorrect type code value"); } Employee kent = Employee.create(ENGINEER)

Example static Employee createEngineer() { return new Engineer(); } static Employee createSalesman() { return new Salesman(); } static Employee createManager() { return new Manager(); } Employee kent = Employee.createEngineer()

Preserve Whole Object You are getting several values from an object and passing these values as parameters in a method call. Send the whole object instead.

Motivation Making the parameter list more robust to changes. Long parameter lists can be hard to work Down side: passing in the required object causes a dependency between the required object and the called object.

Mechanism 1.Create a new parameter for the whole object from which the data comes. 2.Determine which parameters should be obtained from the whole object 3.Take one parameter and replace references to it within the method body by invoking an appropriate method on the whole object parameter. 4.Delete the parameter 5.Compile and test. 6.Repeat for each parameter that can be got from the whole object. 7.Remove the code in the calling method that obtains the deleted parameters 8.Compile and test

Example class Room... boolean withinPlan(HeatingPlan plan) { int low = daysTempRange().getLow(); int high = daysTempRange().getHigh(); return plan.withinRange(low, high); } class HeatingPlan... boolean withinRange (int low, int high) { return (low >= _range.getLow() && high <= _range.getHigh()); } private TempRange _range;

class Room... boolean withinPlan(HeatingPlan plan) { int low = daysTempRange().getLow(); int high = daysTempRange().getHigh(); return plan.withinRange(daysTempRange()); } class HeatingPlan... boolean withinRange (TempRange roomRange) { return (_range.includes(roomRange)); } class TempRange... boolean includes (TempRange arg) { return arg.getLow() >= this.getLow() && arg.getHigh() <= this.getHigh(); }

Replace Parameter with Method An object invokes a method, then passes the result as a parameter for a method. The receiver can also invoke this method. Remove the parameter and let the receiver invoke the method.

Mechanism 1.If necessary, extract the calculation of the parameter into a method. 2.Replace references to the parameter in method bodies with references to the method. 3.Compile and test after each replacement 4.Use Remove Parameter on the parameter

Example public double getPrice() { int basePrice = _quantity * _itemPrice; int discountLevel; if (_quantity > 100) discountLevel = 2; else discountLevel = 1; double finalPrice = discountedPrice (basePrice, discountLevel); return finalPrice; } private double discountedPrice (int basePrice, int discountLevel) { if (discountLevel == 2) return basePrice * 0.1; else return basePrice * 0.05; }

Example private double getPrice () { if (getDiscountLevel() == 2) return getBasePrice() * 0.1; else return getBasePrice() * 0.05; } private int getDiscountLevel() { if (_quantity > 100) return 2; else return 1; } private double getBasePrice() { return _quantity * _itemPrice; }

Introduce Parameter Object You have a group of parameters that naturally go together. Replace them with an object.

Motivation Reduces the size of the parameter lists Once you have clumped together the parameters, you soon see behavior that you can also move into the new class

Mechanism 1.Create a new class to represent the group of parameters you are replacing. Make the class immutable.. 2.Use Add Parameter for the new data clump. Use a null for this parameter in all the callers. 3.For each parameter in the data clump, remove the parameter from the signature. Modify the callers and method body to use the parameter object for that value 4.Compile and test after you remove each parameter. 5.When you have removed the parameters, look for behavior that you can move into the 6.parameter object with Move Method

Example class Entry... Entry (double value, Date chargeDate) { _value = value; _chargeDate = chargeDate; } Date getDate(){ return _chargeDate; } double getValue(){ return _value; } private Date _chargeDate; private double _value; class Account... double getFlowBetween (Date start, Date end) { double result = 0; Enumeration e = _entries.elements(); While (e.hasMoreElements()) { Entry each = (Entry) e.nextElement(); if (each.getDate().equals(start) || each.getDate().equals(end) || (each.getDate().after(start) && each.getDate().before(end))) { result += each.getValue(); } return result; } private Vector _entries = new Vector(); client code... double flow = anAccount.getFlowBetween(startDate, endDate);

Example class Account... double getFlowBetween (DateRange range) { double result = 0; Enumeration e = _entries.elements(); while (e.hasMoreElements()) { Entry each = (Entry) e.nextElement(); if (range.includes(each.getDate())) { result += each.getValue(); } return result; } class DateRange... boolean includes (Date arg) { return (arg.equals(_start) || arg.equals(_end) || (arg.after(_start) && arg.before(_end))); } client code... double flow = anAccount.getFlowBetween(new DateRange(startDate, endDate));

Remove Setting Method A field should be set at creation time and never altered. Remove any setting method for that field.

Example class Account { private String _id; Account (String id) { setId(id); } void setId (String arg) { _id = "ZZ" + arg; } class Account { private final String _id; Account (String id) { initializeId(id); } void initializeId (String arg) { _id = "ZZ" + arg; }

Hide Method A method is not used by any other class.. Make the method private.

Mechanism 1.Check regularly for opportunities to make a method more private Use a lint-style tool, do manual checks every so often, and check when you remove a call to a method in another class 2.Make each method as private as you can. 3.Compile.

Replace Constructor with Factory Method You want to do more than simple construction when you create an object Replace the constructor with a factory method.

Example class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; }

Example static Employee create (String name) { try { return (Employee) Class.forName(name).newInstance(); } catch (Exception e) { throw new IllegalArgumentException ("Unable to instantiate" + name); } static Employee create(int type) { switch (type) { case ENGINEER: return create("Engineer"); case SALESMAN: return create("Salesman"); case MANAGER: return create("Manager"); default: throw new IllegalArgumentException("Incorrect type code value"); } Employee.create("Engineer")

Encapsulate Downcast A method returns an object that needs to be downcasted by its callers Move the downcast to within the method.

Motivation Always provide clients with the most specific type you can Don ’ t put unnecessary work on your clients

Mechanism 1.Look for cases in which you have to downcast the result from calling a method. These cases often appear with methods that return a collection or iterator 2.Move the downcast into the method. With methods that return collections, use Encapsulate Collection.

Examples Object lastReading() { return readings.lastElement(); } Reading lastReading = theSite.lastReading(); class Site... Reading lastReading() { return (Reading) readings().lastElement(); } Reading lastReading() { return (Reading) readings.lastElement(); } Reading lastReading = (Reading) theSite.readings().lastElement()

Replace Error Code with Exception A method returns a special code to indicate an error Throw an exception instead.

Mechanism 1.Decide whether the exception should be checked or unchecked. If the caller is responsible for testing the condition before calling,make the exception unchecked 2.Find all the callers and adjust them to use the exception. If the exception is unchecked, adjust the callers to make the appropriate check before calling the method. If the exception is checked, adjust the callers to call the method in a try block. 3.Change the signature of the method to reflect the new usage 4.Compile and test after each change.

Example class Account... int withdraw(int amount) { if (amount > _balance) return -1; else { _balance -= amount; return 0; } private int _balance;

Example void newWithdraw(int amount) throws BalanceException { if (amount > _balance) throw new BalanceException(); _balance -= amount; } try { account.newWithdraw(amount); doTheUsualThing(); } catch (BalanceException e) { handleOverdrawn(); }

Replace Exception with Test You are throwing a checked exception on a condition the caller could have checked first. Change the caller to make the test first.

Mechanism 1.Put a test up front and copy the code from the catch block into the appropriate leg of the if statement 2.Add an assertion to the catch block to notify you whether the catch block is executed 3.Compile and test. 4.Remove the catch block and the try block if there are no other catch blocks 5.Compile and test.

Example class ResourcePool Resource getResource() { Resource result; try { result = (Resource) _available.pop(); _allocated.push(result); return result; } catch (EmptyStackException e) { result = new Resource(); _allocated.push(result); return result; } Stack _available; Stack _allocated;

Example Resource getResource() { Resource result; if (_available.isEmpty()) result = new Resource(); else result = (Resource) _available.pop(); _allocated.push(result); return result; }