重构视角,如何写“好代码“——组织类篇

173 阅读3分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

确定方法(Method)写在哪个类(Class)

一般类由两部分组成:属性(Field)和行为(Method)。类的行为(Method)就决定了这个类的责任。有时候,我们很难确定某个职责属于哪个类,即这个方法应该写在哪个类上。我们可以采用这个原则:方法与哪个类的属性交集多,就写在哪个类上。

示例:

我们有一个地址类AddressDTO

@Data
public class AddressDTO{
    private Long provinceId;
    private String province;
    private Long cityId;
    private String city;
    private Long countyId;
    private String county;
    private Long townId;
    private String town;
    private String detail;
}

地址类包括:省、市、区、街道、详细地址信息。

现在有一个订单服务类,需要展示订单的收货地址的完整信息:省、市、区、街道、详细地址信息拼在一起就可以了。这个“拼在一起”行为可以写在OrderService

public class OrderService{
    public void show(AddressDTO address){
        // 展示完整地址信息
        String wholeAddress = this.getWholeAddress(address);
    }
    public void getWholeAddress(AddressDTO address){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(address.province).append(address.city).append(address.county).append(address.town).append(address.detail);
    return stringBuilder.toString();
    }
}

更好的做法应该是:“拼在一起”的行为写在AddressDTO类中

@Data
public class AddressDTO{
    private Long provinceId;
    private String province;
    private Long cityId;
    private String city;
    private Long countyId;
    private String county;
    private Long townId;
    private String town;
    private String detail;

    public String wholeAddress() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(province).append(city).append(county).append(town).append(detail);
        return stringBuilder.toString();
    }
}
public class OrderService{
    public void show(AddressDTO address){
        // 展示完整地址信息
        String wholeAddress = address.wholeAddress();
    }
}

确定属性(Field)写在哪个类(Class)

如果类的某个属性被另一个类更多的用到,我们就需要考虑把这个属性放到另外一个类中。

提炼类

我们在开发过程中,要遵循单一原则职责。而一个类承担多个职责时,就违背了该原则。所以,我们在编写类时,如果一个类包含多个职责时,就应该提炼出一个新的类。

隐藏"委托关系"

在面向对象开发过程中,“封装”是非常重要的特性。“封装”可以使我们可以尽可能少的了解系统的其他部分,这样使我们减少代码间依赖。隐藏“委托关系”,可以进一步封装对象。

什么是委托关系?简单来说,就是一个对象委托另一个对象实现某个方法。比如我们有对象A,而对象A的功能需要对象B来完成,我们委托对象B完成,代码表示:

public class A {
    private B b;

    public B getB() {
        return b;
    }
}

public class B {
    public void method() {

    }
}

public class Client {
    public static void main(String[] args) {
        A a = new A();
        a.getB().method();
    }
}

如果类A的功能变化了,A不再需要委托B了,这样的改动将会影响到Client,而Client需要同步修改。我们可以隐藏“委托关系”来解决这样的问题。修改后的代码:

public class A {
    private B b;

    public void method() {
        b.method();
    }
}


public class B {
    public void method() {

    }
}

public class Client {
    public static void main(String[] args) {
        A a = new A();
        a.method();
    }
}

参考

[0] 《重构,改善既有代码的设计》