refactoring tutorial

Click here to load reader

Upload: bingu-shim

Post on 25-Dec-2014

906 views

Category:

Documents


2 download

DESCRIPTION

 

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