您现在的位置是:首页 >其他 >Java代码重构学习笔记-在对象之间搬移特性网站首页其他

Java代码重构学习笔记-在对象之间搬移特性

Logan_addoil 2024-06-14 17:17:16
简介Java代码重构学习笔记-在对象之间搬移特性

Move Method(搬移函数)

它的目的是将一个方法从原始类中搬移到其他类中,从而使类的职责更加清晰明确。

举个例子,假设有一个名为 Customer 的类,其中包含了一个用于计算客户折扣的方法 applyDiscount:

public class Customer {
    private String name;
    private int discount;
    
    public void applyDiscount(double amount) {
        amount *= (1 - discount / 100.0);
        System.out.println(name + " applied a discount of " + discount + "%, the final amount is " + amount);
    }
    
    // getter and setter methods for name and discount
}

在这段代码中,applyDiscount 方法用于计算客户的折扣,并在控制台上输出折扣信息。然而,applyDiscount 方法并没有直接与 Customer 类的数据进行交互,因此可以考虑使用 Move Method 进行重构,将该方法搬移到一个新的 DiscountCalculator 类中,比如:

public class Customer {
    private String name;
    private int discount;
    
    // getter and setter methods for name and discount
    
    public String getName() {
        return name;
    }
    
    public int getDiscount() {
        return discount;
    }
}

public class DiscountCalculator {
    public void applyDiscount(Customer customer, double amount) {
        int discount = customer.getDiscount();
        amount *= (1 - discount / 100.0);
        System.out.println(customer.getName() + " applied a discount of " + discount + "%, the final amount is " + amount);
    }
}

通过 Move Method 重构后,applyDiscount 方法被搬移到了 DiscountCalculator 类中,从而使 Customer 类的职责更加明确,只负责处理与客户信息相关的数据和操作。DiscountCalculator 类则专门用于计算折扣,使得各自的职责更加清晰明确。

需要注意的是,在进行 Move Method 重构时,需要确保新类具有明确的职责,并且确保搬移方法的逻辑正确性和稳定性。同时还需要考虑搬移方法可能涉及到的依赖关系、访问权限和继承关系等,确保程序的整体结构和功能不会发生变化。

Move Field(搬移字段)

它的目的是将一个字段(属性)从一个类中搬移到另一个相关的类中,从而使类的职责更加清晰明确。

举个例子,假设有一个名为 Employee 的类,其中包含了员工的基本信息和员工部门信息,如下所示:

public class Employee {
    private String name;
    private int age;
    private String department;
    
    // setter and getter methods for name, age, department
}

在这段代码中,Employee 类包含了员工名字、年龄和所在部门等信息。然而,随着业务规模扩大,可能需要对员工信息和部门信息进行更加细粒度的管理,因此可以考虑使用 Move Field 进行重构,将 department 字段搬移到一个新的 Department 类中,如下所示:

public class Employee {
    private String name;
    private int age;
    private Department department;

    // getter and setter methods for name, age, department
}

public class Department {
    private String name;

    // getter and setter methods for name
}

通过 Move Field 重构后,Employee 类将员工部门信息委托给一个新的 Department 类来管理,从而使得两个类各司其职,相互独立。在后续对员工和部门信息进行操作时,可以更加方便地控制和管理。

需要注意的是,在进行 Move Field 重构时,要确保新类具有明确的职责,并且需要确保搬移字段的逻辑正确性和稳定性。同时,还需要考虑数据访问权限、继承关系以及可能涉及到的依赖关系等因素,确保程序的整体结构和功能不会发生变化,同时提高代码的可读性和可维护性。

Extract Class(提炼类)

它的目的是将一个类中的一部分职责提取出来,组成一个新的类。这样可以将职责分离,降低类的复杂度,提高代码的可读性和可维护性。

举个例子,假设有一个名为 Person 的类,其中包含了人的基本信息、地址信息和联系方式,如下所示:

public class Person {
    private String name;
    private int age;
    private String street;
    private String city;
    private String zipCode;
    private String phone;
    private String email;
    
    // getter and setter methods for name, age, street, city, zipCode, phone, email
}

在这段代码中,Person 类包含了人的各种信息,然而这些信息并没有很好地进行划分和组织。如果需要对地址信息进行更加详细的管理,可以考虑使用 Extract Class 进行重构,将地址信息以及相关操作提取为一个新的 Address 类。

public class Person {
    private String name;
    private int age;
    private Address address;
    private String phone;
    private String email;
    
    // getter and setter methods for name, age, address, phone, email
}

public class Address {
    private String street;
    private String city;
    private String zipCode;

    // getter and setter methods for street, city, zipCode
}

通过 Extract Class 重构后,Person 类职责更加明确,只负责处理人的基本信息和联系方式,Address 类则专门用于管理地址信息,使得代码更加清晰易懂。在后续修改和扩展时,可以分别对两个类进行操作,减少了代码重复和耦合。

需要注意的是,在进行 Extract Class 重构时,要确保新类具有明确的职责,并且要确保拆分出来的类能够独立完成相应的操作。同时,要考虑数据访问权限、继承关系以及可能涉及到的依赖关系等因素,确保程序的整体结构和功能不会发生变化,同时提高代码的可读性和可维护性。

Inline Class(将类内联化)

它的目的是消除过度抽象的中间层,将一个只有少量属性和方法的类直接合并到另一个类中,从而简化程序的结构。

举个例子,假设有一个名为 Customer 的类,其中只包含了一个名字属性和一个地址属性,如下所示:

public class Customer {
    private String name;
    private Address address;
    
    // getter and setter methods for name, address
}

public class Address {
    private String street;
    private String city;
    private String zipCode;
    
    // getter and setter methods for street, city, zipCode
}

在这段代码中,Customer 类只包含了一个名字属性和一个地址属性,而 Address 类则包含了具体的地址信息。如果 Customer 类只在程序的某个非常狭窄的范围内使用,并且不涉及到地址信息的处理,可以考虑使用 Inline Class 进行重构,将 Customer 类中的属性和方法直接合并到另一个类中。

public class Order {
    private String customerName;
    private String street;
    private String city;
    private String zipCode;
    
    // getter and setter methods for customerName, street, city, zipCode
}

通过 Inline Class 重构后,Customer 类被完全内联到 Order 类中,简化了程序的结构,同时也提高了代码的可读性和可维护性。在后续修改和扩展时,只需要对 Order 类进行操作即可。

需要注意的是,在进行 Inline Class 重构时,要确保被内联的类只有少量的属性和方法,并且没有其他用途。同时,也要考虑程序的继承关系、依赖关系等因素,确保程序的整体结构和功能不会发生变化,同时提高代码的可读性和可维护性。

Hide Delegate(隐藏“委托关系”)

它的目的是减少类之间的耦合程度,将一个类对另一个类的调用关系隐藏起来,从而简化程序的结构。

举个例子,假设有一个名为 Department 的类,其中包含了员工管理的相关信息,如下所示:

public class Department {
    private String name;
    private List<Employee> employees;
    
    // getter and setter methods for name, employees
    
    public Employee getManager() {
        return employees.get(0);
    }
}

在这段代码中,Department 类中包含了一个名字属性和一个员工列表属性,同时定义了一个 getManager() 方法,该方法返回员工列表中的第一个元素,即部门经理。这里存在一个明显的委托关系,即 Department 类委托给 Employee 类来处理部门经理的获取操作。

如果在程序中需要频繁地获取部门经理信息,并且考虑到后续可能会更改获取逻辑,也许应当采用 Hide Delegate 进行重构,将 Department 类中的委托关系隐藏起来,使得其他类不需要直接依赖于 Employee 类。

public class Department {
    private String name;
    private List<Employee> employees;
    
    // getter and setter methods for name, employees
    
    public Employee getManager() {
        return new Manager(employees.get(0));
    }
}

public class Manager {
    private Employee employee;
    
    public Manager(Employee employee) {
        this.employee = employee;
    }
    
    public String getName() {
        return employee.getName();
    }
    
    // other methods related to manager
}

通过 Hide Delegate 重构后,Department 类中的委托关系被隐藏到一个新的 Manager 类中,其他类可以通过 Department 类提供的接口间接获取部门经理信息,而不需要直接依赖于 Employee 类。在后续修改和扩展时,也能够更加方便地进行维护和扩展。

需要注意的是,在进行 Hide Delegate 重构时,要确保隐藏的委托关系能够被其他类所使用,并且不会影响代码的原有功能。同时也要考虑程序的依赖关系、继承关系和设计初衷等因素,确保程序的整体结构和功能不会发生变化,并提高代码的可读性和可维护性。

Remove Middle Man(移除中间人)

它的目的是消除过度抽象的中间层,简化程序的结构,减少不必要的委托关系。

举个例子,假设有一个名为 Person 的类,其中包含了姓名、联系方式等个人信息,同时定义了一个 getPhoneNumber() 方法来获取个人的电话号码,如下所示:

public class Person {
    private String name;
    private String phoneNumber;
    private String email;
    
    // getter and setter methods for name, phoneNumber, email
    
    public String getPhoneNumber() {
        return phoneNumber;
    }
}

在这段代码中,Person 类包含了个人信息的属性和一个用于获取电话号码的方法。假设现在需要获取与该 person 关联的 company 的电话号码,可以通过在 Person 类中添加一个 getCompanyPhoneNumber() 方法实现:

public class Person {
    private String name;
    private String phoneNumber;
    private String email;
    private Company company;
    
    // getter and setter methods for name, phoneNumber, email
    
    public String getPhoneNumber() {
        return phoneNumber;
    }
    
    public String getCompanyPhoneNumber() {
        if (company != null) {
            return company.getPhoneNumber(); // 委托给 Company 对象进行处理
        } else {
            return null;
        }
    }
}

public class Company {
    private String name;
    private String phoneNumber;
    
    // getter and setter methods for name, phoneNumber
}

在这段代码中,Person 类中增加了一个 getCompanyPhoneNumber() 方法,该方法将获取公司电话号码的操作委托给了另一个 Company 类,通过中间的 company 对象来间接获取公司电话号码。

如果考虑到代码的可读性和可维护性,也许可以采用 Remove Middle Man 进行重构,去除不必要的中间层,直接在客户端调用 Company 类中的 getPhoneNumber() 方法。

public class Person {
    private String name;
    private String phoneNumber;
    private String email;
    private Company company;
    
    // getter and setter methods for name, phoneNumber, email
    
    public String getPhoneNumber() {
        return phoneNumber;
    }
    
    public Company getCompany() {
        return company;
    }
}

public class Company {
    private String name;
    private String phoneNumber;
    
    // getter and setter methods for name, phoneNumber
}

// client code
Person person = new Person();
Company company = person.getCompany();
String companyPhoneNumber = company != null ? company.getPhoneNumber() : null;

通过 Remove Middle Man 重构后,Person 类中不再包含 getCompanyPhoneNumber() 方法,而是直接返回 company 对象,在客户端可以直接调用 Company 类中的 getPhoneNumber() 方法,从而消除了过度的中间层,简化了程序的结构,提高了代码的可读性和可维护性。

需要注意的是,在进行 Remove Middle Man 重构时,要确保移除中间层不会影响原有的功能,并且能够提高代码的可读性和可维护性。同时也要考虑程序的依赖关系、继承关系和设计初衷等因素,确保程序的整体结构和功能不会发生变化。

Introduce Foreign Method(引入外加函数)

它的主要目的是在无法修改现有代码的情况下,向对象中添加一个新的方法(即所谓的“外来函数”),以完成特定的操作。

举个例子,假设有一个名为 DateUtil 的工具类,其中包含了一些可以方便地操作日期的静态方法,如下所示:

public class DateUtil {
    public static Date getNextWeekday(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        
        if (dayOfWeek == Calendar.FRIDAY) {
            calendar.add(Calendar.DATE, 3);
        } else if (dayOfWeek == Calendar.SATURDAY) {
            calendar.add(Calendar.DATE, 2);
        } else {
            calendar.add(Calendar.DATE, 1);
        }
        
        return calendar.getTime();
    }
}

在这段代码中,DateUtil 类包含了一个 getNextWeekday() 方法,用于获取下一个工作日的日期。如果需要在另一个类中频繁地使用 getNextWeekday() 方法, 可以考虑使用 Introduce Foreign Method 重构,向该类中添加一个外来函数,使得其他类可以直接调用该函数,而不需要再次访问 DateUtil 类。

public class SomeClass {
    private Date date;
    
    // getter and setter methods for date
    
    public Date getNextWeekday() {
        return DateUtil.getNextWeekday(date);
    }
}

通过 Introduce Foreign Method 重构后,SomeClass 类中添加了一个 getNextWeekday() 方法,该方法直接委托给 DateUtil 类中的 getNextWeekday() 方法进行处理,在客户端可以直接调用 SomeClass 类中的 getNextWeekday() 方法来获取下一个工作日的日期。

需要注意的是,使用 Introduce Foreign Method 重构时要确保该外来函数能够被其他类所使用,并且不会影响原有代码的行为和功能。同时也要考虑程序的依赖关系、继承关系和设计初衷等因素,确保程序的整体结构和功能不会发生变化。

Introduce Local Extension (引入本地扩展)

它的主要目的是在无法修改现有代码的情况下,向现有类中添加新的方法和属性,使其更加灵活和易用。

举个例子,假设有一个名为 Employee 的类,用于表示一个员工对象,该类包含了员工的姓名、工号、月薪等信息。现在需要为该类添加一个新的功能,即计算员工的年终奖金,假设计算公式为月薪的 1.5 倍。但由于不允许修改 Employee 类的源代码,因此不能直接在该类中添加一个计算年终奖金的方法。

这时可以考虑使用 Introduce Local Extension 重构,定义一个子类或者放置在同一个包下的新类,添加一个计算年终奖金的方法,将 Employee 对象作为该方法的参数进行计算。

public class Employee {
    private String name;
    private String id;
    private double monthlySalary;
    
    // getter and setter methods for name, id, monthlySalary
}

public class EmployeeExtension {
    private Employee employee;
    
    public EmployeeExtension(Employee employee) {
        this.employee = employee;
    }
    
    public double getYearEndBonus() {
        return employee.getMonthlySalary() * 1.5;
    }
}

在上述代码中,定义了一个名为 EmployeeExtension 的类,该类包含了一个指向 Employee 对象的引用,同时添加了一个计算年终奖金的方法 getYearEndBonus()。客户端可以通过创建 EmployeeExtension 对象,将 Employee 对象作为参数传入该对象进行操作。

Employee employee = new Employee();
// set employee's name, id, monthlySalary
EmployeeExtension extension = new EmployeeExtension(employee);
double bonus = extension.getYearEndBonus();

通过 Introduce Local Extension 重构后,成功添加了计算年终奖金的功能,同时也保留了原有 Employee 类的功能和行为。需要注意的是,在使用 Introduce Local Extension 重构时,要确保添加的新方法和属性能够满足需求,同时也要考虑程序的依赖关系和设计初衷等因素,确保程序的整体结构和功能不会发生变化。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。