Top Banner

Click here to load reader

of 101

Refactoring tutorial

Dec 25, 2014

Download

Documents

Bingu Shim

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • 1. Tutorial SEEG
  • 2.
  • 3. 3 Confidential 12/13/2011
  • 4. : ? Bad Code Good Code
  • 5. :: Bad Code Broken Window Theory
  • 6. , . Tool Refactoring public int getCharge(int quantity) { public int getCharge(int quantity) { int charge = 0; int charge = 0; Date now = new Date(); Date now = new Date(); // Summer if (isSummerTime(now)) { if (now.before(SUMMER_START)|| now.after(SUMMER_END)) { charge = quantity * WINTER_RATE + charge = quantity * WINTER_RATE + WINTER_SERVICEC_CHARGE; WINTER_SERVICEC_CHARGE; } else { } else { charge = quantity * SUMMER_RATE; charge = quantity * SUMMER_RATE; } } return charge; return charge } } private boolean isSummerTime(Date now) { return now.before(SUMMER_START) || now.after(SUMMER_END); }
  • 7. : ? ? ?
  • 8. : ? , , . ,
  • 9. : (10~30), .
  • 10. : Publish Ex) Android Service.onStart() I/F Delegation : API Publish Throw Delegation : Super Exception , ?
  • 11. : , . With design I can think very fast, but my thinking is full of little holes Alistair Cockburn Role , . . . Complexity
  • 12. : . . , .
  • 13. () Switch
  • 14. : Obvious Copy & Paste Unobvious (ex, , ) ExtractMethod ExtractMethod -> Pull Up Field or Pull Up Method -> Form Template Method
  • 15. : . People often make assumptions based on the object names alone Word Cunningham Rename Method Rename Field Rename Constants Tip ! add, register, put, create -> add
  • 16. : PriceCalculator Product .. calculate() .. getQuantity() bmethod() getDiscountRate() Move Method
  • 17. : Class A Class B (private .. .. ) amethod() xmethod() bmethod() ymethod() Move Method Change Bidirectional Reference to Unidirectional Extract Hierarchy-> Hide Delegate
  • 18. : Extract Method Rename Method Introduce Assertion
  • 19. : . Extract Method .
  • 20. : . Replace Parameter with Method Object Preserve Whole Object Introduce Parameter Object Caller Callee
  • 21. : Switch Switch , Switch OOP Switch Switch Step 1: Extract Method Step 2: Move Method Step 3: Replace Type Code with Subclass or Replace Type Code with State/Strategy Switch 21 Confidential 12/13/2011
  • 22. . , . . 22 Confidential 12/13/2011
  • 23. 23 Confidential 12/13/2011
  • 24. 24 Confidential 12/13/2011
  • 25. : .
  • 26. : -> - -> Extract Method -> Rename Method -> Introduce Assertion
  • 27. : - package ch3;public class Matcher { public Matcher() { } [Rename Method] // . public boolean compare(int[] expected, int[] actual, int clipLimit, int delta) { // clipLimit . [Extract Method] for (int i = 0; i < actual.length; i++) if (actual[i] > clipLimit) actual[i] = clipLimit; // . [Extract Method] if (actual.length != expected.length) return false; // delta . for (int i = 0; i < actual.length; i++) if (Math.abs(expected[i] - actual[i]) > delta) return false; return true; }} 27 Confidential 12/13/2011
  • 28. Refactoring : Extract Method .{ { // clipLimit . // clipLimit . for (int i = 0; i < actual.length; i++) for (int i = 0; i < actual.length; i++) if (actual[i] > clipLimit) if (actual[i] > clipLimit) actual[i] = clipLimit; actual[i] = clipLimit; }} private void cutLargeValues(int[] values, int limit) { for (int i = 0; i < values.length; i++) if (valuesl[i] > limit) values [i] = limit; } 28 Confidential 12/13/2011
  • 29. Refactoring : Rename Method . !! 29 Confidential 12/13/2011
  • 30. Refactoring : Introduce Assertion assertion double getExpenseLimit() { double getExpenseLimit() { // should have either expense limit or a primary project return Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); (_expenseLimit != NULL_EXPENSE) ? return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _expenseLimit: _primaryProject.getMemberExpenseLimit(); _primaryProject.getMemberExpenseLimit();} } Assertion . Assertion Assertion . Assertion Assertion Extract Method 30 Confidential 12/13/2011
  • 31. : - . , -> , , ? -> ExtractMethod
  • 32. : -> Extract Class -> Extract Subclass -> Extract Interface
  • 33. Refactoring : Extract Class , , ! 33 Confidential 12/13/2011
  • 34. Refactoring : Extract Class 34 Confidential 12/13/2011
  • 35. Refactoring : Extract Subclass JobItem +getTotalPrice() JobItem +getUnitPrice() +getTotalPrice() +getUnitPrice() +getEmployee() LaborItem +getUnitPrice() +getEmployee() Extract Class Extract Subclass Extract Subclass (variation) . . Extract Class (variation) . , . 35 Confidential 12/13/2011
  • 36. Refactoring : Extract Interface , Billable +getRate() Employee +hasSpecialSkill() +getRate() +hasSpecialSkill() +getName() Employee +getDepartment() +getRate() +hasSpecialSkill() +getName() +getDepartment() Extract Superclass Extract Interface . 36 Confidential 12/13/2011
  • 37. : - Coupling . -> Replace Parameter with Method -> Preserve Whole Object -> Introduce Parameter Object Coupling
  • 38. Refactoring : Replace Parameter with Method , . , Int basePrice = quantity * itemPrice; int basePrice = quantity * itemPrice;discountLevel = getDiscountLevel(); double finalPrice = getDiscountedPrice(basePrice);double finalPrice = getDiscountedPrice(basePrice, discountLevel);
  • 39. Refactoring : Preserve Whole Object Int low = daysTempRange().getLow();Int high = daysTempRange().getHigh(); withinPlan = plan.withinRange(daysTempRange());withinPlan = plain.withinRange(low, high) , ,
  • 40. Refactoring : Introduce Parameter Object -> -> ,
  • 41. 41 Confidential 12/13/2011
  • 42. : . : , : , , (Type Embedded in Name) (Uncommunicative Name) (Inconsistent Name)
  • 43. : ex) addCourse(Course c) ex) iCount -> , -> -> Rename Method, Rename Field, Rename Constant , .
  • 44. : Rename Method, Rename Field, Rename Constant * , .
  • 45. : . Ex) add(), store(), put(), place(), register() . -> Rename Method, Rename Field, Rename Constant , .
  • 46. 46 Confidential 12/13/2011
  • 47. 47 Confidential 12/13/2011
  • 48. : & , , , , , , . . . . -> Collapse Hierarchy -> Inline Class -> Inline Method -> -> Remove Parameter , , , .48 Confidential 12/13/2011
  • 49. Refactoring : Inline Class & Collapse Hierarchy* Inline Class .* Collapse Hierarchy LoginContext LoginModule +authenticate() Collapse Hierarchy IDPasswordLoginModule KerberosLoginModule x x FingerPrintLoginModule +authenticate() +authenticate() +authenticate() 49 Confidential 12/13/2011
  • 50. Refactoring : Inline Method .int getRating() { int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; return (_numberOfLateDeliveries > 5) ? 2 : 1;} }boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5;} Indirection Refactoring Refactoring 50 Confidential 12/13/2011
  • 51. 51 Confidential 12/13/2011
  • 52. : . . . . (Magic Number) (Duplicated Code) (Alternative Classes with Different Interfaces)
  • 53. : . Replace Magic Number with Symbolic Constant ,
  • 54. : public void analyze(File file) throws FileNotFoundException { private static final int INDEX_TYPE = 0; BufferedReader reader = new BufferedReader(new FileReader(file)); private static final int INDEX_TIME = 1; private static final int INDEX_URL = 2; try { private static final int INDEX_IPADRESS = 3; String aLine = reader.readLine(); public void analyze(File file) throws FileNotFoundException { while (aLine != null) { BufferedReader reader = new BufferedReader(new FileReader(file)); // type, time, id, ip address String[] record = aLine.split(SEPERATOR); try { String aLine = reader.readLine(); AccessLog aLog = new AccessLog(); aLog.setType(record[0]); while (aLine != null) { aLog.setTime(record[1]); // type, time, id, ip address aLog.setUrl(record[2]); String[] record = aLine.split(SEPERATOR); aLog.setIpAddress(record[3]); Replace Magic Number with Symbolic Constant AccessLog aLog = new AccessLog(); aLine = reader.readLine(); aLog.setType(record[INDEX_TYPE]); } aLog.setTime(record[INDEX_TIME]); } catch (IOException e) { aLog.setUrl(record[INDEX_URL]); e.printStackTrace(); aLog.setIpAddress(record[INDEX_IPADRESS]); } finally { // .. aLine = reader.readLine(); } }} } catch (IOException e) { e.printStackTrace(); } finally { // .. } } , 54 Confidential 12/13/2011
  • 55. : . . Copy & Paste -> Extract Method -> Extract Method -> Pull Up Field or Pull Up Method -> Form Template Method -> Extract Class , -> Substitute Algorithm .
  • 56. : 56 Confidential 12/13/2011
  • 57. : , -> Rename Method -> Move Method, Add Parameter, Parameterize Method -> Extract Superclass -> .
  • 58. 58 Confidential 12/13/2011
  • 59. : ? Boolean (Complicated Boolean Expression) (Simulated Inheritance) 59 Confidential 12/13/2011
  • 60. : Boolean , , ) public boolean isAcceptable1(int score, int income, boolean authorized) { if (!((score > 700) || ((income >= 40000) && (income 500)) || (income > 100000)) ) return false; else return true; } DeMorgans Law)public boolean isAcceptable2(int score, int income, boolean authorized) { if (((score 100000) || !authorized || (score = 40000) && (income 500)) || (income > 100000)) ) return false; else return true; } Introduce Explaining Variable) public boolean isAcceptable3(int score, int income, boolean authorized) { boolean hasMidRangeIncome = (income >= 40000) && (income 100000;; boolean hasHighScore = score > 700; if (!( hasHighScore || (hasMidRangeIncome && authorized && (score > 500)) || hasHighIncome) ) return false; else return true; } 61 Confidential 12/13/2011
  • 62. Refactoring : Introduce Explaining Variable & DeMorgans LawIntroduce Explaining Variable) public boolean isAcceptable3(int score, int income, boolean authorized) { boolean hasMidRangeIncome = (income >= 40000) && (income 100000;; boolean hasHighScore = score > 700; if (!( hasHighScore || (hasMidRangeIncome && authorized && (score > 500)) || hasHighIncome) ) return false; else return true; } Introduce Explaining Variable) & DeMorgans Law public boolean isAcceptable4(int score, int income, boolean authorized) { boolean hasMidRangeIncome = (income >= 40000) && (income 100000;; boolean hasHighScore = score > 700; if (!hasHighScore && (!hasMidRangeIncome || !authorized || !(score > 500)) && !hasHighIncome) return false; else return true; } 62 Confidential 12/13/2011
  • 63. Refactoring : Decompose Conditional) public boolean isAcceptable1(int score, int income, boolean authorized) { if (!((score > 700) || ((income >= 40000) && (income 500)) || (income > 100000)) ) return false; else return true; } Decompose Conditional) public boolean isAcceptable5(int score, int income, boolean authorized) { if (!(isHighScore(score) || ( isMidRangeIncome(income) && authorized && isMidScore(score)) || isHighIncome(income)) ) return false; else return true; } 63 Confidential 12/13/2011
  • 64. Refactoring : Decompose Conditional) public boolean isAcceptable5(int score, int income, boolean authorized) { if (!(isHighScore(score) || ( isMidRangeIncome(income) && authorized && isMidScore(score)) || isHighIncome(income)) ) return false; else return true; } ) public boolean isAcceptable6(int score, int income, boolean authorized) { if (isHighScore(score) || ( isMidRangeIncome(income) && authorized && isMidScore(score)) || isHighIncome(income) ) return true; else return false; } 64 Confidential 12/13/2011
  • 65. Refactoring : Consolidate Conditional Expression ) public boolean isAcceptable1(int score, int income, boolean authorized) { if (!((score > 700) public|| ((income >= 40000) && (income 500)) { || (income > 100000)) ) ifreturn false; (isHighScore(score) else|| ( isMidRangeIncome(income) && authorized && isMidScore(score)) || isHighIncome(income) return true; } ) return true; else return false; } Consolidate Conditional ExpressionConsolidate Conditional Expression) public boolean isAcceptable8(int score, int income, boolean authorized) { if (isHighScore(score) || isHighIncome(income)) // return true; if (isMidRangeIncome(income) && authorized && isMidScore(score)) return true; else Refactoring return false; } - - - 65 Confidential 12/13/2011
  • 66. Boolean 66 Confidential 12/13/2011
  • 67. : public class Employee { private int type; private static final int ENGINEER = 0; 1 private static final int SALESMAN = 1; private static final int MANAGER = 2; public Employee(int type) { this.type = type; Type } Replace Type Code with public int calculatePayment() { switch (type) { case ENGINEER: return monthlySalary; State/Strategy case SALESMAN: return monthlySalary + commission; case MANAGER: return monthlySalary + bonus; Replace Type Code with default: throw new RuntimeException("Incorrect Employee"); Subclass }} public String getJobTitle() { 2 switch (type) { case ENGINEER: Replace Conditional with return "Engineer"; case SALESMAN: Class return "Salesman"; case MANAGER: return "Manager"; default: throw new RuntimeException("Incorrect Employee"); } }} 67 Confidential 12/13/2011
  • 68. Boolean 68 Confidential 12/13/2011
  • 69. 69 Confidential 12/13/2011
  • 70. 70 Confidential 12/13/2011
  • 71. : Book Book height title genre category width author weight price getDiscount() getRequiredDeliveryRoom() content Book , , 71 Confidential 12/13/2011
  • 72. : ->Replace Data Value with Object -> : Replace Type Code with Class : Replace Array with Object 72 Confidential 12/13/2011
  • 73. Refactoring : Replace Data with Object User +firstName: String +lastName: String Order Customer Replace Data with+orderNumber: String Object Order +firstName: String+customeFirstNamer: String 1 1 +lastName: String+customerLastName: String +orderNumber+price: float+addressState: String Address+addressCity: String +state+addressStreet: String +city+addressZipCode1: String +zipCode1+addressZipCode 2: String 1 1 +zipCode2+telAreaCode: String+telNumber: String +getDeliveryCost() home Contact office +areaCode +number 73 Confidential 12/13/2011
  • 74. Refactoring : Replace Array with Object String[] row = new String[3]; Performance row = new Performance(); row [0] = "Liverpool"; row.setName("Liverpool"); row [1] = "15"; row.setWins("15"); 74 Confidential 12/13/2011
  • 75. : public field getter/setter 1- : Encapsulate Field 2- : Remove Setting Method 3-Collection : Encapsulate Collection 4- : Extract Method and Move Method 5- , , public , getter/setter 75 Confidential 12/13/2011
  • 76. Refactoring : Encapsulate Collection Collection get/set (read-only view) , add/remove Collection (get) Collection . Collection (set) Collection Collection . 76 Confidential 12/13/2011
  • 77. Encapsulate Collection 77 Confidential 12/13/2011
  • 78. 78 Confidential 12/13/2011
  • 79. : .( ) .( ) . , Is-A , Replace Inheritance with Delegation Extract Subclass, Push Down Field, Push Down Method , . -> Java Collection79 Confidential 12/13/2011
  • 80. : Drawable Drawable +draw() Line +draw() Exception +getArea() +getArea() , 0 Rectangle Circle Rectangle Circle Line +getArea() Drawable +draw() Shape Line +getArea() +getLength() Rectangle Circle80 Confidential 12/13/2011
  • 81. Liskov Substitution Principle(LSP)Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. , Square Rectangle . -> , LSP . Shape Rectangle.setWidth() Square.setWidth() . +getArea() Shape Rectangle Circle +getArea() +width+height+setWidth()+setHeight()+getWidth() Square Rectangle Circle+getHeight() +width +width +height +height +setLength() +setWidth() +setHeight() Square +getWidth() +getHeight()OOD IS-A .81 Confidential 12/13/2011
  • 82. Refactoring : Replace Inheritance with Delegation 82 Confidential 12/13/2011
  • 83. : ( ) (private ) . . -> Self Encapsulate Field -> Form Template Method -> Replace Inheritance with Delegation 83 Confidential 12/13/2011
  • 84. Refactoring : Form Template Method , , , , , .84 Confidential 12/13/2011
  • 85. : , Delegation. . -> Collapse Hierarchy -> Inline Class .85 Confidential 12/13/2011
  • 86. 86 Confidential 12/13/2011
  • 87. : 87 Confidential 12/13/2011
  • 88. : & Class A Class B Class A Class B .. .. .. attributeA amethod() getX() amethod() bmethod() getY() bmethod() amethod() private . - Move Method Move Method - Extract Hierarchy-> Hide Delegate - Change Bidirectional Reference to Unidirectional88 Confidential 12/13/2011
  • 89. Refactoring : Hide Delegate , (Delegate) . Client Department . Law of Demeter . : . 89 Confidential 12/13/2011
  • 90. Refactoring : Change Bidirectional Association to Unidirectional . Bidirectional Association . -> Zombie Cluster -> Coupling 90 Confidential 12/13/2011
  • 91. : & Remove Middleman Hide Delegate . person.getDepartment().getManager() Delegate Feature . Server . . . Delegate Feature Server . . Hide Delegate Remove Middleman ! , . 91 Confidential 12/13/2011
  • 92. 92 Confidential 12/13/2011
  • 93. : (Divergent Change) (Parallel Inheritance Hierarchies) (Combinational Explosion) (Shotgun Surgery) 93 Confidential 12/13/2011
  • 94. : (Divergent Change) Shape Shape ShapWriter +draw() +draw() +persist() +persist() 5px .. Binary , XML .. Rectangle Circle Triangle RectangleWriter CircleWriter TriangleWriter Rectangle Circle Triangle +draw() +draw() +draw() +persistence() +persistence() +persistence() +draw() V +draw() V +draw()V +persist() V +persist() V +persist() V . . Extract Class Class . 94 Confidential 12/13/2011
  • 95. : SRP Test Method Uses , Used History ? 95 Confidential 12/13/2011
  • 96. : Shape ShapWriter +draw() +persist() Rectangle Circle Triangle RectangleWriter CircleWriter TriangleWriter +draw() +draw() +draw() +persistence() +persistence() +persistence() -> . Move Method, Move Field 96 Confidential 12/13/2011
  • 97. : ShapeWriter Triangle +persist() ? DB ? Rectangle Circle +draw() +draw() RectangleExcelWriter RectangleXmlWriter RectangleExcelWriter RectangleXmlWriter (or Concern) . Replace Inheritance with Delegation Tease Apart Inheritance 97 Confidential 12/13/2011
  • 98. Refactoring : Tease Apart Inheritance , . , . 98 Confidential 12/13/2011
  • 99. : (Shotgun Surgery) . . . Move Method, Move Field & Persistence 99 Confidential 12/13/2011
  • 100. 100 Confidential 12/13/2011
  • 101. : . Introduce Foreign Method Introduce Local Extension [Introduce Local Extension] 101 Confidential 12/13/2011