Your SlideShare is downloading. ×
重構—改善既有程式的設計(chapter 8)part 2
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

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

951

Published on

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

  • Be the first to like this

No Downloads
Views
Total Views
951
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
54
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

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

×