重构改善代码设计-笔记

目录

1、案例

(1)原代码

(2)优化思路

2、需要重构的迹象

3、重构手法

(1)重新组织函数

(2)在对象之间搬移特性

(3)重新组织数据

(4)简化条件表达式

(5)简化函数调用

(6)处理概括关系

(7)大型重构


1、案例
(1)原代码
//电影类
public class Movie {
    //有三种类型的电影 0常规电影 1、新电影 2、儿童影片
    public static final int REGULAR= 0;
    public static final int NEW_RELEASE =1;
    public static final int CHILDRENS=2;
    //影片名和影片类型
    private String title;
    private int priceCode;
    
    public Movie(String title, int priceCode) {
        this.title = title;
        this.priceCode = priceCode;
    }
    public int getPriceCode () {    return priceCode;    }
    public void setPriceCode (int priceCode) {
        this.priceCode = priceCode;
    }
    public String getTitle () {    return title;    }
}

//租赁类
public class Rental {
    //租赁的电影,和租时长
    private Movie movie;
    private int daysRented;
    public Rental(Movie movie,int daysRented){
        this.movie = movie;
        this.daysRented = daysRented;
    }
    public int getDaysRented(){    return daysRented;    }
    public Movie getMovie(){    return movie;    }
}

//顾客类
public class Customer{
    // 顾客名称 租赁的影片数组
    private String name;
    private List<Rental> list;
    public Customer(String name){
        this.name = name;
        this.list = new ArrayList<>();
    };
    //添加要租赁的
    public void addRental(Rental rental) {
        list.add(rental);
    }
    public String getName () {    return name;    }

    public String statement(){
        //总金额
        double totalAmount =0;
        //积分
        int frequentRenterPoints=0;
        for (Rental rental : list) {
            double thisAmount= 0;
            switch(rental.getMovie().getPriceCode()){
                case Movie.REGULAR:
                    //常规影片,固定价格2元,租赁超过2元,每天1.5元
                    thisAmount += 2;
                    if (rental.getDaysRented()>2){
                        thisAmount +=(rental.getDaysRented()-2)*1.5;
                    }
                    break;
                case Movie.NEW_RELEASE:
                    //新出的影片 每天3元
                    thisAmount += rental.getDaysRented()*3;
                    break;
                case Movie.CHILDRENS:
                    //儿童片 固定1,5元 租赁超过3元,每天1.5元
                    thisAmount += 1.5;
                    if (rental.getDaysRented()>3){
                        thisAmount +=(rental.getDaysRented()-3)*1.5;
                    }
                    break;
                default:
                    break;
            }
            totalAmount+=thisAmount;
            //积分计算,每组一部影片,积分+1
            frequentRenterPoints++;
            //如果租的是新电影,且租期大于1天的,每部新电影再给一个积分
            if (rental.getMovie().getPriceCode()==Movie.NEW_RELEASE &&
            rental.getDaysRented()>1){
                frequentRenterPoints++;
            }
        }
        String result = "顾客"+getName()+ "\n消费:"+totalAmount+"\n积分:"+frequentRenterPoints;
        return result;
    }
}
(2)优化思路

问题:

1、需求:会改变影片分类规则,会影响费用和积分计算,影片要支持多种扩展

2、statement太长,功能太多,需要分解重组(放到适合的类中,不要写在一起)

解决思路:

1、先建立可靠的测试环境,一步一测试,避免bug

2、不要一个循环把所有事情都做了,例如在一个循环中进行金额计算和积分计算,可以分成两个循环,抽成两个方法,一个专门算金额,一个专门算积分

3、金额计算和积分计算都与影片相关,不同的影片种类,租赁金额和积分方式不同。每种影片一个类,有个各自的金额和积分,使用多态

4、面对对象编程,不要面对过程编程

5、去除临时变量,变量命名通俗易懂

2、需要重构的迹象

事不过三,三则重构

  • 见名知义
  • 重复代码
    • 提出方法,推入超类,设成模版,或者放入间接层,被调用,总之将重复代码合而为一
  • 过长函数
    • 通过注释,确定结构和范围,拆分方法(所以要打好注释啊,不然看起来好麻烦)
  • 过大的类
    • 拆分类,根据功能拆成同级类,也可以拆接口,抽象类,子类
  • 过长参数列
    • 参数太多,同一对象内的就直接使用对象,方便传输也方便增加参数。没有对象归属的,也可以制造出一个对象
  • 发散式变化
    • 一个类,能引发他改动的东西太多了,职责太多了。拆分,最好是单一职责。
  • 霰弹式修改
    • 一种变化引发多个类修改,需要修改的代码散布四处。把一系列相关行为放进同一个类
  • 依恋情结
    • 某个函数为了计算某个值,从另一个对象那里调用了几乎半打的值,显而易见,要将此函数移到适合的位置去,总之把依恋的部分要抽出来,移动到适合的地方去
  • 数据泥团
    • 相同的数据字段,可以抽出来,例如很多类都有的id,创建时间等
  • 基本类型偏执
    • 不愿意创建对自己的问题域有用的对象,如钱、坐标、范围等,而是全部使用基本类型。
  • 重复的switch
  • 冗余的类,未来可能用到的功能(但实际没能用到)该删就删
  • 消息链太长,a.getB().getC().getD()

3、重构手法
(1)重新组织函数
  • Extract Method(提炼函数)
    • 提出方法,取名知义,就算函数名称比提炼出来的代码还长也无所谓
  • Inline Method(内联函数)
    • 方法本体太简单,没必要抽象成方法,直接使用吧
  • Inline Temp(内联临时变量)
    • 临时变量用的少,没必要定义,直接使用a.getB()也行
  • Replace Temp with Query(以查询取代临时变量)
    • 这样会不会影响性能,1、影响不了多少,2、就算影响了,重构后代码组织良好,方便找到优化方案 3、恢复原来的代码也方便
//案例1
private double getPrice(){
    int basePrice = quantity * itemPrice;
    double discountFactory;
    if (basePrice>1000){
        discountFactory=0.95;
    }else {
        discountFactory=0.98;
    }
    return basePrice*discountFactory;
}

//用方法代替basePrice
private double getPrice(){
    double discountFactory;
    if (getBasePrice()>1000){
        discountFactory=0.95;
    }else {
        discountFactory=0.98;
    }
    return getBasePrice()*discountFactory;
}
private int getBasePrice() {
    returnquantity * itemPrice;
}

//用方法代替discountFactory
private double getPrice(){
    return getBasePrice()*getDiscountFactory();
}

private double getDiscountFactory() {
    if (getBasePrice()>1000){
        return 0.95;
    }else {
        return 0.98;
    }
}

private int getBasePrice() {
    return quantity * itemPrice;
}
  • Introduce Explaining Variable(引入解释性变量)
    • 比如if...else...中判断的表达式太长,先变成临时变量
    • 比如计算价格不要一个长算式全部算出来了,多用几个临时变量一步步算清楚
  • Split Temporary Variable(分解临时变量)
    • 临时变量,它既不是循环变量,也不用于收集计算结果,还被多次赋值,说明他有多个作用,每次赋值创建不同的临时变量不行吗,保持单一功能
  • Remove Assignments to Parameters(移除对参数的赋值)
    • 对方法的传入参数进行操作可以,把参数改变指向另一个对象,有问题
  • Replace Method with Method Object(以函数对象取代函数)
//原逻辑
class Account {
   private int gamma(int inputVal, int quantity, int yearToDate) {
      int importantValue1 = (inputVal * quantity) + delta();
      int importantValue2 = (inputVal * quantity) + 100;
      if ((yearToDate - importantValue1) > 100) {
         importantValue2 -= 20;
      }
      int importantValue3 = importantValue2 * 7;
      return importantValue3 - 2 * importantValue1;
   }
   private int delta() {    return 200;    }
}

//以函数对象取代函数
class Gamma{
   private final Account account;
   private int inputVal;
   private int quantity;
   private int yearToDate;
   private int importantValue1;
   private int importantValue2;
   private int importantValue3;

   public Gamma(Account account, int inputVal, int quantity, int yearToDate) {
      this.account = account;
      this.inputVal = inputVal;
      this.quantity = quantity;
      this.yearToDate = yearToDate;
   }

   int computer(){
      importantValue1 = (inputVal * quantity) + account.delta();
      importantValue2 = (inputVal * quantity) + 100;
      if ((yearToDate - importantValue1) > 100) {
         importantValue2 -= 20;
      }
      importantValue3 = importantValue2 * 7;
      return importantValue3 - 2 * importantValue1;
   }
}

class Account {
    private int gamma(int inputVal, int quantity, int yearToDate) {
       return new Gamma(this,inputVal,quantity,yearToDate).computer();
    }
    private int delta() {
      return 200;
   }
}
  • Substitute Algorithm(替换算法)
    • 如果有更优秀的实现方法,那就改
(2)在对象之间搬移特性

决定把责任放在哪

  • Move Method(搬移函数)
  • Move Field(搬移字段)
  • Extract Class(提炼类)
  • Inline Class(将类内联化)
    • 一个类不再有单独存在的理由,并入另一个类,和提炼类相反
  • Hide Delegate(隐藏“委托关系”)
class Person{
    //员工所属部门
   Department department ;
   public Department getDepartment(){
      return department;
   }
   public void setDepartment(Department arg){
      department = arg;
   }
}
class Department {
    //部门经理
   private Person manager;
   public Department(Person manager){
      this.manager = manager;
   }
   public Person getManager() {
      return manager;
   } 
}
//要想获得员工上级经理
manager = person.getDepartment().getManager();

//隐藏这个关系,在person中增加获取经理的方法
public Person getManager() {
   return department.getManager();
}
manager = person.getManager();
  • Introduce Foreign Method(引入外加函数)
    • 需要给某个类增加一个多次调用的函数,但无法修改这个类,只能外加函数
Date newstart = new Date (previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDate()+1);
//给Date一个外加函数
Date newStart  = nextDay(previousEnd);
private static Date nextDay(Date arg){
    return new Date (arg.getYear(),arg.getMonth(), arg.getDate()+ 1);
}    
  • Introduce Local Extension(引入本地扩展)
    • 要添加额外函数,但不能改原类--》建立原类的子类或包装类去添加额外函数
//包装类举例
class MyDateWrap{
    private Date original;
    public MyDateWrap(Date arg){
        original = arg;
    }
    public MyDateWrap(String dataString){
        original = new Date(dateString);
    }
}
(3)重新组织数据
  • Self Encapsulate Field(自封装字段)
    • privite+设置函数 VS public+直接访问
  • Replace Data Value with Object(以对象取代数据值)
    • 比如订单类中有客户名称,客户可以单独提出一个对象,方便客户扩展
  • Change Value to Reference(将值对象改为引用对象)
    • 引用对象:可变的,每个对象都代表真实世界中的一个实物
    • 值对象:不可变的,完全由其所含的数据值来定义,可以存在重复的成百上千个。类似日期、钱这样的东西。
    • 有时候,从一个简单的值对象开始,其中保存不可修改的数据,而后,希望加入一些可修改的数据--》值对象变为引用对象
//现在一笔订单有一个对应的客户信息
public class Customer {
    private String name;
    public Customer (String name){    this.name = name;    }
    public String getName() {    return name;    }
}

public class Order {
    private Customer customer;
    public Order(String customerName) {
        this.customer = new Customer(customerName);
    }
    public void setCustomer(String customerName) {
        this.customer = new Customer(customerName);
    }
    public String getCustomerName() {
        return customer.getName();
    }
}
到目前为止,Customer对象还是值对象。就算多份订单属于同一客户,但每个order对象还是拥有各自的customer对象。
我希望改变这一现状,使得一旦同一客户拥有多份不同订单,代表这些订单的所有order对象就可以共享同一个Customer对象。
这就意味着:每一个客户名称只该对应一个customer对象。--》修改customers的构造方式--》工厂模式
  • Change Referenceto Value(将引用对象改为值对象)
  • Duplicate Observed Data(复制“被监视数据”)
    • 将处理业务逻辑的和处理用户界面的区分开--》观察者模式extends Observable
  • Change Unidirectional Association to Bidirectional(将单向关联改为双向关联)
//订单Order单向关联Customer
public class Order {
    Customer customer;
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

//让customer反向关联,一个用户可以有多份订单
public class Customer {
    private Set<Order> orders = new HashSet<>();
    Set<Order> friendOrder(){
        return orders;
    }
}

//让哪个类来控制关联关系,如果是一对多,让1控制,如果是多对多,都可以
//让order来控制关联关系
public class Order {
    Customer customer;
    public void setCustomer(Customer customer) {
        this.customer = customer;
        customer.friendOrder().add(this);
    }
}
  • Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)
  • Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)
    • 不要使用魔法值,定义成常量
  • Encapsulate Field(封装字段)
    • public封装成private
  • Encapsulate Collection(封装集合)
    • 同上,对集合搞个设值函数,add,remove之类的,不要直接暴露
  • Replace Record with Data Class(以数据类取代记录)
    • 创建类用来记一些数据
  • Replace Type Code with Class(以类取代类型码)
public class PersonB {
    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 PersonB() {
    }
    public int getBloodGroup() {
        return bloodGroup;
    }
    public void setBloodGroup(int bloodGroup) {
        this.bloodGroup = bloodGroup;
    }
}

//以类取代类型码
public 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[] valuse ={O,A,B,AB};
    private final int code;
    public BloodGroup(int code) {
        this.code = code;
    }
}

public class PersonB {
    private BloodGroup bloodGroup;
    public PersonB(BloodGroup bloodGroup) {
        this.bloodGroup = bloodGroup;
    }
    public BloodGroup getBloodGroup() {
        return bloodGroup;
    }
    public void setBloodGroup(BloodGroup bloodGroup) {
        this.bloodGroup = bloodGroup;
    }
}
  • Replace Type Code with Subclasses(以子类取代类型码)
public class Employee {
    private int type;
    static final  int ENGINEER =0;
    static final  int SALESMAN =1;
    static final  int MANAGER =2;
    //构造工厂
    static Employee create(int type){
        switch (type){
            case ENGINEER:
                return new Enginerer();
            case SALESMAN:
                return new Salesman();
            case MANAGER:
                return new Manager();
            default:
                throw new IllegalArgumentException("111");
        }
    }
    int getType(){
        return type;
    }
}
  • Replace Type Code with State/Strategy(以状态模式或者策略模式取代类型码)
public class Employee {
    private int type;
    static final  int ENGINEER =0;
    static final  int SALESMAN =1;
    static final  int MANAGER =2;
    int monthlySalary=10;
    int comm=2;
    int bou=5;
    int payAmount(){
        switch (type){
            case ENGINEER:
                return monthlySalary;
            case SALESMAN:
                return monthlySalary+comm;
            case MANAGER:
                return monthlySalary+bou;
            default:
                throw new IllegalArgumentException();
        }
    }
    int getType(){
        return type;
    }
}

//重构后
public abstract class EmployeeType {
    static final  int ENGINEER =0;
    static final  int SALESMAN =1;
    static final  int MANAGER =2;
    abstract int getTypeCode();
    public static EmployeeType newType(int code) {
        switch (code){
            case ENGINEER:
                return new Engineer();
            case MANAGER:
                return new Manager();
            case SALESMAN:
                return new Salesman();
            default:
                throw new IllegalArgumentException("code");
        }
    }
}

public class Engineer extends EmployeeType{
    @Override
    int getTypeCode() {
        return ENGINEER;
    }
}

public class Manager extends EmployeeType{
    @Override
    int getTypeCode() {
        return MANAGER;
    }
}

public class Salesman extends EmployeeType{
    @Override
    int getTypeCode() {
        return SALESMAN;
    }
}

public class Employee {
    private EmployeeType type;
    int monthlySalary=10;
    int comm=2;
    int bou=5;

    int payAmount(){
        switch (getType()){
            case EmployeeType.ENGINEER:
                return monthlySalary;
            case EmployeeType.SALESMAN:
                return monthlySalary+comm;
            case EmployeeType.MANAGER:
                return monthlySalary+bou;
            default:
                throw new IllegalArgumentException();
        }
    }

    int getType(){
        return type.getTypeCode();
    }

    public void setType(int arg) {
        this.type = EmployeeType.newType(arg);
    }
}
  • Replace Subclass with Fields(以字段取代子类)
    • 各个子类的唯一差别只在返回常量函数身上,就没有足够的存在价值,可以挪到父类销毁子类了
public abstract class Person {
    abstract  boolean isMale();
    abstract  char getCode();
}
public class Male extends Person {
    @Override
    boolean isMale() {    return true;    }
    @Override
    char getCode() {    return 'M';    }
}
public class Female extends Person {
    @Override
    boolean isMale() {    return false;    }
    @Override
    char getCode() {    return 'F';    }
}

//删除子类
public class Person1{
    private final boolean isMale;
    private final char code;
    static Person1 createMale(){
        return new Person1(true,'M');
    }
    static Person1 createFemale(){
        return new Person1(false,'F');
    }
    private Person1(boolean isMale, char code) {
        this.isMale = isMale;
        this.code = code;
    }
    public boolean isMale() {
        return isMale;
    }
    public char getCode() {
        return code;
    }
}
(4)简化条件表达式
  • Decompose Conditional(分解条件表达式)
    • 复杂的条件表达式分解成小块函数
  • Consolidate Conditional Expression(合并条件表达式)
if(onVacation()){
    if(lengthOfService()>10){
        return 1;
    }
}
return 0.5;

return (onVacation() && lengthOfService()>10)? 1:0.5;
  • Consolidate Duplicate Conditional Fragments(合并重复的条件片段)
    • 比如if...else的每个条件都执行了send()方法,那就可以把send()方法合并了提出来
  • Remove Control Flag(移除控制标记)
    • 比如while循环通过flag标记值的改变跳出循环,那我们可以不使用flag,直接在值改变时,break或者return
  • Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式)
    • 就是if..else中某条件能直接返回的就直接返回,不要if...else嵌套下去
  • Replace Conditional with Polymorphism(以多态取代条件表达式)
    • 就是switch变成多态,建一个抽象父类,几个子类,各有不同实现
  • Introduce Nul Object(引入 Null 对象)
public class Site {
    private Customer customer;
    public Customer getCustomer() {
        return customer;
    }
}
public class Customer {
    private String name;
    private BillingPlan plan;
    private PaymentHistory history;
    public Customer() {    }
    public String getName() {    return name;    }
    public BillingPlan getPlan() {    return plan;    }
    public PaymentHistory getHistory() {    return history;    }
}
获取Customer中的一些数据总要判断从Site拿到的Customer是否为空

//建一个空对象
public class NullCustomer extends Customer{
    @Override
    public boolean isNull() {    return true;    }
    @Override
    public String getName() {
        return "给个空对象应该对应的默认值";
    }
    @Override
    public BillingPlan getPlan() {
        return super.getPlan();
    }
    @Override
    public PaymentHistory getHistory() {
        return super.getHistory();
    }
}
public class Customer {
    private String name;
    private BillingPlan plan;
    private PaymentHistory history;
    public Customer() {    }
    public static Customer newNull() {
        return new NullCustomer();
    }
    public boolean isNull(){
        return false;
    }
    ...
}

public class Site {
    private Customer customer;
    public Customer getCustomer() {
        return (customer==null)? Customer.newNull():customer;
    }
}
  • Introduce Assertion(引入断言)
    • assert
(5)简化函数调用
  • Rename Method(函数改名)
  • Add Parameter(添加参数)
  • Remove Parameter(移除参数)
    • 程序员可能经常添加参数,却往往不愿意去掉它们
  • Separate Query from Modifier(将查询函数和修改函数分离)
    • 某个函数既修改对象状态值,又修改对象状态,就可以分开,一个负责修改,一个负责查询
  • Parameterize Method(令函数携带参数)
    • 若干函数做了类似的工作,但在函数本体中却包含了不同的值。建议单一函数,以参数表达哪些不同的值。
private Dollars baseCharge(){
    double result = Math.min(lastUsage(),100)*0.3;
    if (lastUsage()>100){
        result += (Math.min(lastUsage(),200)-100)*0.05;
    }
    if (lastUsage()>200){
        result += (lastUsage()-200)*0.07;
    }
    return  new Dollars(result);
}

//抽象建立单一函数,找出重复的规律,不同的值通过传入参数
private Dollars baseCharge(){
    double result = usageInRange(0,100)*0.3;
    result += usageInRange(100,200)*0.05;
    result += usageInRange(200,Integer.MAX_VALUE)*0.07;
    return  new Dollars(result);
}

private double usageInRange(int start, int end) {
    if (lastUsage()>start){
        return Math.min(lastUsage(),end)-start;
    }else {
        return 0;
    }
}
  • Replace Parameter with Explicit Methods(以明确函数取代参数)
private void setValue(String name,int value){
    if ("height".equals(name)){
        height=value;
        return;
    }
    if ("weight".equals(name)){
        weight=value;
        return;
    }
}
//优化后
private void setHeight(int arg){
    height=arg;
}
private void setWeight(int arg){
    weight=arg;
}
  • Preserve Whole Object(保持对象完整)
    • 将来自同一对象的若干数据作为参数传递给某个函数,改为将整个对象传过去
  • Replace Parameter with Methods(以函数取代参数)
    • 减少传递参数,如果可以通过方法直接内部拿,那就不要在外部拿了,然后又作为参数传进去
  • Introduce Parameter Object(引入参数对象)
    • 某些参数总数同时出现,比如开始时间和结束时间,传参的时候可以将这些一同出现的一组数组搞成对象来传
  • Remove Setting Method(移除设值函数)
    • 如果类中某个字段只在创建时被赋值,后面就不再改变了。那么就不要提供设值函数
  • Hide Method(隐藏函数)
    • 一些方法的可见度修改,比如取值和设值函数,不用就没必要放出来
  • Replace Constructor with Factory Method(以工厂函数取代构造函数)
  • Encapsulate Downcast(封装向下转型)
Object lastReading(){
    return readings.lastElement();
}
Reading lastReading(){
    return (Reading) readings.lastElement();
}
  • Replace Error Code with Exception(以异常取代错误码)
private  int withdraw(){
    if (amount>banlance){
        return -1;
    }else {
        banlance=amount;
        return 0;
    }
}
private void withdraw(int amount) throws BalanceException {
    if (amount>banlance){
        throw new BalanceException();
    }
    banlance = amount;
}
  • Replace Exception with Test(以测试取代异常)
    • 能先通过判断避免异常发生的,那就先判断,不要滥用异常。比如分母为0,就可以提前判断出来
(6)处理概括关系
  • Pull Up Field(字段上移)
    • 子类有相同的字段,移至超类
  • Pul Up Method(函数上移)
  • Pull Up Constructor Body(构造函数本体上移)
    • 尽量用到父类的构造函数
  • Push Down Method(函数下移)
  • Push Down Field(字段下移)
  • Extract Subclass(提炼子类)
    • 类中某些行为只被一部分实例用到,其他实例用不到,建个子类吧
public class JobItem {
    private  int unitPrice;    //单价
    private  int quantity;    //数量
    private  Employee employee;    //员工
    private boolean isLabor;    //是否按零件收费
    public JobItem(int unitPrice, int quantity, Employee employee, boolean isLabor) {
        this.unitPrice = unitPrice;
        this.quantity = quantity;
        this.employee = employee;
        this.isLabor = isLabor;
    }
    public int getTotalPrice() {    return getUnitPrice()*quantity;    }
    public int getUnitPrice() {
        return isLabor? employee.getRate():unitPrice;
    }
    public int getQuantity() {    return quantity;    }
    public Employee getEmployee() {    return employee;    }
}

public class Employee {
    private int rate;
    public Employee(int rate){
        this.rate = rate;
    }
    public int getRate() {    return rate;    }
}

//优化后
public class JobItem {
    private  int unitPrice;
    private  int quantity;
    public JobItem(int unitPrice, int quantity) {
        this.unitPrice = unitPrice;
        this.quantity = quantity;
    }
    public int getTotalPrice() {    return getUnitPrice()*quantity;    }
    public int getUnitPrice() {    return unitPrice;    }
    public int getQuantity() {    return quantity;    }
    public boolean isLabor() {    return false;    }
}

public class LaborItem extends JobItem {
    private  Employee employee;
    public LaborItem(int unitPrice, int quantity, Employee employee) {
        super(unitPrice, quantity);
        this.employee = employee;
    }
    @Override
    public int getUnitPrice() {    return employee.getRate();    }
    @Override
    public boolean isLabor() {    return true;    }
}
  • Extract Superclass(提炼超类)
    • 两个类以相同的方式做类似的事,建立超类
  • Extract Interface(提炼接口)
  • Collapse Hierarchy(折叠继承体系)
    • 超类和子类之间无太大区别,将它们合为一体
  • Form TemPlate Method(塑造模板函数)
  • Replace Inheritance with Delegation(以委托取代继承)
    • 某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据
  • Replace Delegation with inheritance(以继承取代委托)
(7)大型重构
  • Tease ApartInheritance(梳理并分解继承体系)
    • 某个继承体系同时承担两项责任,建立两个继承体系,并通过委托关系让其中一个可以调用另一个
  • Convert Procedural Design to Objects(将过程化设计转化为对象设计)
  • Separate Domain from Presentation将(领域和表述/显示分离)
    • MVC(模型-视图-控制器)
    • 将展示层和实现逻辑分离
  • Extract Hierarchy(提炼继承体系)
    • 某个类做了太多工作,其中一部分工作是以大量条件表达式完成的。建立继承体系,以一个子类表示一种特殊情况
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值