重構—改善既有程式的設計(chapter 8)part 2

1,449 views

Published on

Published in: Education, Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,449
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
67
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

重構—改善既有程式的設計(chapter 8)part 2

  1. 1. Hubert Chan<br />Refactoring – chap 8-2<br />
  2. 2. 8.9 Replace Magic Number with Symbolic Constant<br />Magic Number 特性<br />具有特殊意義,卻又不能明確表現出其意義。<br />可讀性差 / 不明確 / 牽一髮動全身<br />解決方案<br />以 Constant 取代Magic Number<br />double potentialEngery(double mass, double height) {<br /> return mass * 9.81 * height<br />}<br />double potentialEngery(double mass, double height) {<br /> return mass * GRAVITATIONAL_CONSTANT * height<br />}<br />static final double GRAVITATIONAL_CONTSTANT = 9.81;<br />
  3. 3. 8.9 Replace Magic Number with Symbolic Constant<br />Refactoring 時機<br />Magic Number 是 Type Code<br />Replace Type Code With Class<br />陣列長度<br />使用 Array.length()<br />關鍵字<br />const<br />static<br />final<br />
  4. 4. 8.10 Encapsulate Field<br />class A {<br /> public String _name;<br />}<br />class A {<br />private String _name;<br /> public String getName() {return _name;}<br /> public void setName(String arg) {_name = arg;}<br />}<br />
  5. 5. 8.10 Encapsulate Field<br />動機<br />封裝 Encapsulation<br />資料隱藏 Data Hiding<br />public 欄位:資料可以被修改、存取,但是擁有的物件卻無法控制其行為<br />改變存取資料為(Objective-C 2.0 property)<br />readonly<br />readwrite<br />assign<br />copy<br />
  6. 6. 8.11 Encapsulate Collection<br />目的<br />傳回 Collection 的一個 readonly view<br />提供 add/remove 元素的 function<br />
  7. 7. 8.11 Encapsulate Collection<br />動機<br />Getter 不該傳回 collection 本身<br />暴露過多實作細節<br />使用者可以存取 getter 拿到的 collection<br />使用 add/remove 函式添加元素<br />使用者不用管底層使用哪種 Collection(List, Array, Vector)<br />
  8. 8. 8.11 Encapsulate Collection<br />class Course {<br /> public Course (String name, booleanisAdvanced) {}<br /> public booleanisAdvanced() {}<br />}<br />Class Person { public Set getCourses() {<br /> return _courses; }<br /> public void setCourses(Set arg) {<br /> _courses = arg; }<br /> private Set _courses;<br />}<br />//使用者直接操作 data<br />//直接 assign,非複製<br />
  9. 9. 8.11 Encapsulate Collection<br />Person kent = new Person();<br />Set s = new HashSet();<br />s.add(new Course("Smalltalk Programming", false));<br />s.add(new Course("Appreciating Single Malts", true));<br />kent.setCourses(s);<br />Course refact = new Course("Refactoring", true);<br />kent.getCourses().add(refact);<br />kent.getCourses().remove(refact);<br />//直接 assign,非複製<br />//使用者直接操作 data<br />//使用者直接操作 data<br />
  10. 10. 8.11 Encapsulate Collection<br />Refactoring for JAVA 1.2 – <br />使用 add/remove 函式<br />Class Person {<br /> public void addCourse(Course arg) {<br /> _courses.add(arg); }<br /> public void removeCourse(Course arg)<br /> _courses.remove(arg); }<br /> public void initializeCourses(Set arg) {<br />Assert.isTrue(_courses.isEmpty());<br />_courses.addAll(arg); }<br />}<br />//內部的 _courses != arg<br />
  11. 11. 8.11 Encapsulate Collection<br />Refactoring for JAVA 1.2 – <br />使用 add/remove 函式<br />Person kent = new Person();<br />Set s = new HashSet();<br />s.add(new Course("Smalltalk Programming", false));<br />s.add(new Course("Appreciating Single Malts", true));<br />kent.setCourses(s);<br />Person kent = new Person();<br />kent.addCourse(new Course("Smalltalk Programming", false));<br />kent.addCourse(new Course("Appreciating Single Malts", true));<br />
  12. 12. 8.11 Encapsulate Collection<br />Refactoring for JAVA 1.2 – <br />不該讓使用者透過 getter 修改物件內的 collection<br />Getter 回傳 unmodified set<br />kent.getCourses().add(new Course("C Programming", false));<br />Class Person {<br /> public Set getCourse() {<br />return Collections.unmodifiableSet(_courses);}<br />}<br />//回傳 unmodifiable的 Set<br />
  13. 13. 8.11 Encapsulate Collection<br />將行為移至 class 內<br />Move Method<br />更好維護<br />class Person {<br />intnumberOfAdvancedCourses(Person person) { Iterator iter = person.getCourses().iterator();<br />int count = 0;<br /> while (iter.hasNext()) {<br /> Course each = (Course) iter.next();<br /> if (each.isAdvanced()) count++; }<br /> return count;<br /> }<br />}<br />
  14. 14. 8.12 Replace Record with Data Class<br />手法<br />把傳統的 record structure 轉為 data class<br />使用 getter/setter<br />class Person {<br /> String getName() {<br /> return _name; }<br /> String setName(String arg) {<br /> _name = arg; }<br /> private String _name;<br />}<br />class PersonRecord {<br /> public char[] name;<br />}<br />
  15. 15. 8.13 Replace Type Code with Class<br />目的<br />Type Code 沒有型別檢驗<br />Type Code => Class,factory class 可以做型別檢驗<br />
  16. 16. 8.13 Replace Type Code with Class<br />目標是 Person 中的 Type Code<br /> class Person {<br /> public static final int O = 0;<br /> public static final int A = 1;<br /> public static final int B = 2;<br /> public static final int AB = 3;<br /> private int _bloodGroup;<br /> public Person (intbloodGroup) {<br /> _bloodGroup = bloodGroup;<br /> }<br /> public void setBloodGroup(intarg) {<br /> _bloodGroup = arg;<br /> }<br /> public intgetBloodGroup() {<br /> return _bloodGroup;<br /> }<br /> }<br />//型別是 int,不是特別的型別<br />
  17. 17. 8.13 Replace Type Code with Class<br />把 Person 中 Type Code 換成 BloodGroup Class<br /> class BloodGroup {<br /> public static final BloodGroup O = new BloodGroup(0);<br /> public static final BloodGroup A = new BloodGroup(1);<br /> public static final BloodGroup B = new BloodGroup(2);<br /> public static final BloodGroup AB = new BloodGroup(3);<br /> private static final BloodGroup[] _values = {O, A, B, AB};<br /> private finalint _code;<br />privateBloodGroup (int code ) {<br /> _code = code;<br /> }<br /> public intgetCode() {<br /> return _code;<br /> }<br /> public static BloodGroup code(intarg) {<br /> return _values[arg];<br /> }<br /> }<br />//class instance 而非 Type Code<br />//constructor 是 private<br />
  18. 18. 8.13 Replace Type Code with Class<br />使用 Class 並維持原本的對外介面<br /> class Person {<br /> public static final int O = BloodGroup.O.getCode();<br /> public static final int A = BloodGroup.A.getCode();<br /> public static final int B = BloodGroup.B.getCode();<br /> public static final int AB = BloodGroup.AB.getCode();<br />private BloodGroup _bloodGroup;<br /> public Person (intbloodGroup) {<br /> _bloodGroup = BloodGroup.code(bloodGroup);<br /> }<br /> public intgetBloodGroup() {<br /> return _bloodGroup.getCode();<br /> }<br /> public void setBloodGroup(intarg) {<br /> _bloodGroup = BloodGroup.code (arg);<br /> }<br /> }<br />
  19. 19. 8.13 Replace Type Code with Class<br />在 Constructor 使用 Class 做參數<br />為新的介面加入 setter/getter<br /> class Person { <br /> public Person (BloodGroupbloodGroup) {<br /> _bloodGroup = bloodGroup;<br /> }<br /> public void setBloodGroup(BloodGrouparg) {<br /> _bloodGroup = arg;<br />}<br /> public BloodGroupgetBloodGroup() {<br /> return _bloodGroup;<br /> }<br /> }<br />//使用 BloodGroup<br />// Setter<br />// Getter<br />
  20. 20. 8.13 Replace Type Code with Class<br />使用者端的改變<br />Person thePerson = new Person(PersonA);<br />thePerson.getBloodGroupCode();<br />thePerson.setBloodGroup(Person.AB);<br />Person thePerson = new Person(BloodGroup.A);<br />thePerson.getBloodGroup();<br />thePerson.setBloodGroup(BloodGroup.AB);<br />
  21. 21. 8.14 Replace Type Code with Subclasses<br />使用時機<br />有一個 type code 會影響 class 的行為<br />為了 Replace Conditional with Polymorphism 鋪路<br />彰顯「特定類別的行為」<br />
  22. 22. 8.14 Replace Type Code with Subclasses<br />目標 class<br />具有會影響行為的 type code<br /> class Employee{<br /> private int _type;<br /> static final int ENGINEER = 0;<br /> static final int SALESMAN = 1;<br /> static final int MANAGER = 2;<br /> Employee (int type) {<br /> _type = type;<br />}<br />}<br />//Type Code<br />
  23. 23. 8.14 Replace Type Code with Subclasses<br />在 Base Class 將行為的 function 抽出來<br />getType()<br /> class Employee{<br />abstractintgetType();<br />}<br /> class Engineer extends Employee {<br />intgetType() {<br /> return Employee.ENGINEER; }<br />}<br />//abstract 強制 subclass 需要 implement<br />// implement<br />
  24. 24. 8.14 Replace Type Code with Subclasses<br />修改 factory class<br /> class Employee {<br /> static Employee create(int type) {<br />switch (type) {<br /> case ENGINEER:<br /> return new Engineer();<br /> case SALESMAN:<br /> return new Salesman();<br /> case MANAGER:<br /> return new Manager();<br /> default:<br /> ...<br /> }<br /> }<br />//getType邏輯在各類別中<br />
  25. 25. 8.14 Replace Type Code with Subclasses<br />Refactoring 之後<br />把只與各個類別相關的函式放在類別中<br />Push Down Method<br />Push Down Field<br />
  26. 26. 8.15 Replace Type Code with State/Strategy<br />使用時機<br />有一個 type code 他會影響 class 行為<br />無法使用 subclassing,例如 type 可變<br />手法<br />以 state object 取代 type code<br />比較 Replace Type Code with Class<br />
  27. 27. 8.15 Replace Type Code with State/Strategy<br />目標:將 type code 以 state object 取代<br /> class Employee{<br /> private int _type;<br /> static final int ENGINEER = 0;<br /> static final int SALESMAN = 1;<br /> static final int MANAGER = 2;<br /> Employee (int type) {<br /> _type = type;<br />}<br />}<br />//Type Code<br />
  28. 28. 8.15 Replace Type Code with State/Strategy<br />觀察:如何使用 type code<br /> class Employee{<br />intpayAmount() {<br /> switch (_type) {<br /> case ENGINEER:<br /> return _monthlySalary;<br /> case SALESMAN:<br /> return _monthlySalary + _commission;<br /> case MANAGER:<br /> return _monthlySalary + _bonus;<br /> default:<br /> throw new RuntimeException("Incorrect Employee");<br /> }<br />}<br />}<br />//依照 Type Code 進行運算<br />
  29. 29. 8.15 Replace Type Code with State/Strategy<br />設計 state object / 共有 state 的部份<br />使用 abstract class / abstract function<br /> abstract class EmployeeType {<br /> abstract intgetTypeCode();<br /> }<br /> class Engineer extends EmployeeType {<br />intgetTypeCode () {<br /> return Employee.ENGINEER;<br /> }<br /> }<br />//abstract function<br />//subclass implementation<br />
  30. 30. 8.15 Replace Type Code with State/Strategy<br />改變 state 時,改變 state object 的 class<br /> class Employee...<br /> private EmployeeType _type;<br /> void setType(intarg) {<br /> switch (arg) {<br /> case ENGINEER:<br /> _type = new Engineer();<br /> break;<br /> case SALESMAN:<br /> _type = new Salesman();<br /> break;<br /> case MANAGER:<br /> _type = new Manager();<br /> break;<br /> default:<br /> ...<br /> }<br /> }<br />//很像 factory pattern<br />//搬出去?<br />
  31. 31. 8.15 Replace Type Code with State/Strategy<br />將 factory method 放到 state object<br /> class Employee...<br /> void setType(intarg) {<br /> _type = EmployeeType.newType(arg);<br /> }<br />class EmployeeType...<br /> static EmployeeTypenewType(int code) {<br /> switch (code) {<br /> case ENGINEER:<br /> return new Engineer();<br /> case SALESMAN:<br /> return new Salesman();<br /> case MANAGER:<br /> return new Manager();<br /> default:<br /> ...<br /> }<br /> }<br /> static final int ENGINEER = 0;<br /> static final int SALESMAN = 1;<br /> static final int MANAGER = 2;<br />//setter 使用 state class 的 factory method<br />// state class 的 factory method<br />
  32. 32. 8.15 Replace Type Code with State/Strategy<br />以 state object 的 state 進行運算<br />接著可以用 Replace Conditional with Polymorphism<br /> class Employee...<br />intpayAmount() {<br /> switch (getType()) {<br /> case EmployeeType.ENGINEER:<br /> return _monthlySalary;<br /> case EmployeeType.SALESMAN:<br /> return _monthlySalary + _commission;<br /> case EmployeeType.MANAGER:<br /> return _monthlySalary + _bonus;<br /> default:<br />...<br /> }<br /> }<br />
  33. 33. 8.16 Replace Subclass with Fields<br />使用時機<br />Subclass 的 function 是 constant method<br />可以透過回傳一個 field 來取代 constant method<br />
  34. 34. 8.16 Replace Subclass with Fields<br />觀察<br />abstract method 都只是回傳 hard-code 資料<br /> abstract class Person {<br /> abstract booleanisMale();<br /> abstract char getCode();<br /> ...<br /> class Male extends Person {<br />booleanisMale() {<br /> return true;<br /> }<br /> char getCode() {<br /> return 'M';<br /> }<br /> }<br />//return hard-code<br />//return hard-code<br />
  35. 35. 8.16 Replace Subclass with Fields<br />以 Factory Method 隱藏 subclass 類別<br />設定 subclass 的 constructor 為 private<br />未來可以移除 subclass<br /> class Person...<br /> static Person createMale(){<br /> return new Male();<br /> }<br /> static Person createFemale() {<br /> return new Female();<br /> }<br />
  36. 36. 8.16 Replace Subclass with Fields<br />為 superclass 加上想要取代的 field<br /> class Person...<br /> protected Person (booleanisMale, char code) {<br /> _isMale = isMale;<br /> _code = code;<br />}<br />booleanisMale() {<br /> return _isMale;<br />}<br />class Male...<br /> Male() {<br /> super (true, 'M');<br />}<br />//以 Field 取代 subclass 的 function<br />
  37. 37. 8.16 Replace Subclass with Fields<br />移除無用的 subclass<br /> class Person<br /> static Person createMale(){<br /> return new Person(true, 'M');<br /> }<br />//以 factory pattern 抽換類別<br />

×