如何用最小代价重构你的构造函数

在重构老项目的过程当中,咱们不难发现常常会有这样的代码:构造函数不少(我的认为超过2个以上的构造函数所属的类,就有必要进行一番修改了),每每不知道如何维护,遇到版本迭代的时候,若是要修改以前的老代码则显的信心不足,只能在里面加补丁,代码习惯好点的可能加补丁的时候还会增长一点注释,代码习惯差一点的注释都没有。时间久了这部分代码就成了屎山,并且这个类也变的愈来愈难以维护。本文就从几个维度上教你如何重构相似的场景。程序员

下面是一个支付结果的类,看看相似的代码风格在你的项目中有没有(若是真的没有说明大家的团队技术水平真的很好,建议点击右上角关闭本文,不要浪费时间)安全

//支付渠道
interface PayChannel {

}
//银行渠道
class BankChannel implements PayChannel {

}
//微信
class WxChannel implements PayChannel {

}
//支付宝
class AliPayChannel implements PayChannel {

}
复制代码
/**
 * 支付结果类
 */
public class PayResult {
    //支付渠道
    private PayChannel payChannel;
    //支付时间
    private Date payDate;
    //订单总金额
    private Double totalValue;
    //实际支付金额
    private Double paymentValue;
    //用券抵消的金额
    private Double couponValue;
    //贷款支付的金额
    private Double loanValue;

    //银联支付 没有 用券的资格 也没有用贷款支付的资格
    public PayResult(Date payDate, Double totalValue, Double paymentValue) {
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;

        this.payChannel = new BankChannel();
        this.loanValue = 0.0d;
        this.paymentValue = 0.0d;
    }

    //微信支付没有贷款支付的能力
    public PayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.payChannel = new WxChannel();
        this.loanValue = 0.0d;
    }


    public PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }

}
复制代码

能够看出来PayResult这个类 仅仅有六个字段,可是构造函数就达到了三个。很很差维护。并且一般在项目里,这样的基础类可能用到的地方不少不少,咱们一时半会也不敢随意大改,怕引起线上故障bash

相似于:微信

public class TestMain {
    public static void main(String[] args) {
        PayResult p1 = new PayResult(new Date(), 3.1d, 3.1d);
        PayResult p2 = new PayResult(new AliPayChannel(), new Date(), 5.2d, 3.2d, 3.1d, 0.1d);
        PayResult p3 = new PayResult(new Date(), 3.1d, 2.1d, 1.0d);

    }
}
复制代码

调用的地方太多,压根不敢随便大改。毕竟重构的首要条件是不要引起线上故障。那么有没有较为温和的方式可以优化一下这样的代码呢? 毕竟其实上述的构造函数里面的重复代码也挺多的,构造函数越多,重复代码的伤害就越大。碰到这种状况,咱们一般会利用构造函数连接来完成重构,就是指:特殊的构造函数会调用更通用的构造函数,直到到达最后一个构造函数。 讲白了,其实就是让多余的构造函数之间经过this.构造函数 来进行一个收敛,决绝重复代码,仅此而已。这样改起来,不会形成侵入性过大,维护成本也较小。函数

例如:微信支付

//银联支付 没有 用券的资格 也没有用贷款支付的资格
    public PayResult(Date payDate, Double totalValue, Double paymentValue) {
        this(new BankChannel(), payDate, totalValue, paymentValue, 0.0d, 0.0d);
    }

    //微信支付没有贷款支付的能力
    public PayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        this(new WxChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);

    }

    //这个就是全包构造函数了 构造函数最全的就能够称之为全包构造函数,当咱们的构造函数过多的时候
    //就能够将多余的构造函数都最终指向咱们的全包构造函数,这是一个收敛的过程
    public PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }
复制代码

改完之后就很简单,咱们将咱们的构造函数进行了统一的收敛,这在业务负载,改动频繁的场景中会变的十分好用, 不会由于增长删除或者变动了某些字段而引起大面积改动。优化

若是是一个有代码洁癖的人,改到这里也会以为不舒服,还想继续改。由于这样改完虽然可以部分解决构造函数复杂,维护成本巨大的问题,可是代码的可读性却没有改观。ui

对于构造函数来讲,可读性很是很是重要。本质上来讲,若是一个类的构造函数越多,那么程序员犯错的可能性就越高,由于你构造函数太多了,多到你的构造函数自己没法有效和高效的表达你的意图。this

并且对于不少终年累月的老项目来讲,不少构造函数甚至都过期了,根本没人用。可是由于可读性的问题,敢删掉他们的人很少。spa

下面继续介绍一种方法,看看能不能在改动不大的状况下,重构咱们的代码,把可读性给提升一下。

//银联支付
    public static PayResult createUnionPayResult(Date payDate, Double totalValue, Double paymentValue) {
        return new PayResult(new BankChannel(), payDate, totalValue, paymentValue, 0.0d, 0.0d);
    }

    //微信支付
    public static PayResult createWxPayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        return new PayResult(new WxChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);
    }

    //支付宝支付
    public static PayResult createAliPayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        return new PayResult(new AliPayChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);
    }


    //注意这个时候咱们的全包构造函数 变成了private
    private PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }
复制代码

增长了几个静态的create 函数,而后将咱们的全包构造函数进行收敛 设置为private. 极大的限制了调用者的权限, 从而在必定程度上能够避免程序员的犯错。 并且这种改动也不会伤筋动骨,对于老的代码调用处来讲,只要更换一下函数名便可:

public class TestMain {
    public static void main(String[] args) {
        PayResult p1 =  PayResult.createUnionPayResult(new Date(), 3.1d, 3.1d);
        PayResult p2 =  PayResult.createAliPayResult(new AliPayChannel(), new Date(), 5.2d, 3.2d, 3.1d, 0.1d);
        PayResult p3 =  PayResult.createWxPayResult(new Date(), 3.1d, 2.1d, 1.0d);

    }
}
复制代码

这样看起来,不但可读性大大提高,安全性也较好,不再用担忧有其余同事用错了。

相关文章
相关标签/搜索