在重构老项目的过程当中,咱们不难发现常常会有这样的代码:构造函数不少(我的认为超过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);
}
}
复制代码
这样看起来,不但可读性大大提高,安全性也较好,不再用担忧有其余同事用错了。