1 / 25

Refactoring

Refactoring. Originally prepared for COMP314, Bernhard Pfahringer see also: links on the COMP204 page Code Complete, Chapter 24. Refactoring definition.

virgo
Download Presentation

Refactoring

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. Refactoring Originally prepared for COMP314, Bernhard Pfahringer see also: links on the COMP204 page Code Complete, Chapter 24

  2. Refactoring definition • “change to the internal structure of software to make it easier to understand and cheaper to change, WITHOUT changing the observable behaviour” (Martin Fowler, 1999) • I.e. changes “inside the black box” only

  3. Key points • Program changes are a fact of life • Change => degrade or improve • “code smells” indicate need for change • know different refactorings (esp. IDE support …) • use safe strategy • do it early on

  4. Examples • What is wrong with this: public void sendEmail(String message, Employee recipient) { … … recipient.getEmailAddress(); … recipient.getName(); } recipient type too specific: • missed potential for reuse • worse: potential for misuse: … recipient.approveRaise(10000) …

  5. Solution one: primitive types • Only provide what is really needed using primitives including strings (or similar “value” or immutable types): public void sendEmail(String message, String address, String name) { … … address …; … name …; } Cons: many parameters, must change all callers

  6. Solution two: Interface • Define Interface which provides only what is needed (e.g. only read access, can even mimic C++ const declarations) public interface Addressee { String getEmailAddress(); String getName(); } public class Employee implements Addressee { … }

  7. Solution two continued public void sendEmail(String message, Addressee recipient) { … … recipient.getEmailAddress(); … recipient.getName(); } • no need to change any callers • easy extension, e.g. add functionality to Addressee, like boolean prefersPlainText()

  8. Decompose complex condition • Extract code into separate methods with meaningful names: 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); }

  9. Reverse conditional if (notSummer(date)) { charge = winterCharge(quantity); } else { charge = summerCharge(quantity); } if (isSummer(date)) { charge = summerCharge(quantity); } else { charge = winterCharge(quantity); } Unless there is no ELSE branch …

  10. Define Null objects X x = computeX(…); if (x != null) { x.methodZ(); } If there is a: class NullX extends X { … methodZ() …} Then computeX(…) can return it if needed, => no NullPointerException, the following is safe X x = computeX(…); x.methodZ();

  11. Replace Constructors with Factory methods public final class Boolean { private boolean value; private Boolean(boolean value) { this.value = value; } public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static Boolean getValue(boolean value) { if (value) return Boolean.TRUE; return Boolean.FALSE; } }

  12. Safe refactoring (similar for code performance tuning) • ensure rollback (e.g. via svn) • small steps, one at a time • always test (unit tests, and more) • bug fixing is NOT refactoring • refactor early

  13. “Code smells” • code is duplicated • a method is too long • a loop is too long or too deeply nested • class has poor cohesion • class interface does not provide consistent level of abstraction • parameter list has too many parameters • changes within a class are compartmentalized • change requires parallel mods in mult.classes • inheritance hierarchies must be modified in parallel

  14. more code smells • case statements modified in parallel • related data not organized into classes • method uses more features of another class than its own • primitive data type is “overloaded” • class does not too very much • chain of methods passes “tramp data” • middleman object doing nothing • class relies on internals of another • method has a poor name • public data members/fields

  15. and even more code smells • subclass uses only small parts of its parent’s methods • comments explain too complex code • use of global variables • method must use complex setup code before and/or takedown code after calling another method • code not needed now, but maybe in the future

  16. Types of refactorings • Data level refactorings • Statement-level refactoring • Method-level refactoring • Class implementation refactoring • Class interface refactoring • System-level refactorings

  17. Data level refactorings • replace magic number with named constant • rename variable to clearer informative name • move expression inline • replace expression with method call • introduce intermediate variable • replace multi-use variable with single-use variables

  18. More Data level refactorings • Use local variable instead of parameter (use final in parameter list) • convert primitive data to class • convert type codes to enumeration • or to class with sub-classes • change array to an object • encapsulate collection

  19. Statement-level refactoring • decompose boolean expression • replace complex boolean exp. with well-named method • consolidate code fragments of different parts of conditional statement • Use break/continue/return in loops • Return/break early • use polymorphism instead of switch • use “null” objects

  20. Method-level refactoring • extract a method • move method call inline • turn a long routine into a class • replace complex algorithm with a simple one • add a parameter • remove a parameter

  21. more Method-level refactoring • separate query from modification • combine similar methods by parameterization • separate methods • pass one whole object instead of many specific fields (cf “Addressee”) • pass specific fields instead of object • encapsulate downcasting

  22. Class implementation refactoring • change value object to reference object • change reference object to value object • replace method with data initialization • change member data or method placement • extract specialised code into subclass • combine similar code into superclass

  23. Class interface refactoring • move method into another class • split class into two • remove a class • hide a delegate • remove a middleman • replace inheritance by composition • replace composition by inheritance • introduce “foreign” method • introduce extension class

  24. more Class interface refactoring • encapsulate exposed data fields • remove unwanted set methods • hide methods that are intended for use outside a class • encapsulate unused methods • collapse sub with superclass if very similar

  25. System-level refactorings • create reference source for data outside your control • change bi-directional class association to uni-directional • change uni-directional class association to bi-directional • Provide factory method instead of a constructor • replace error code with exceptions and v.v.

More Related