架构师书房-《代码不朽》-消除重复代码的技巧

架构师书房-《代码不朽》-消除重复代码的技巧

首页休闲益智代号点消更新时间:2024-05-13

大家好,我是码农老吴,欢迎收看架构师书房。今天,我继续给大家解读《代码不朽》这本书。

上期,我们聊了本书的第三个原则,不写重复代码(Write Code Once)。知道了代码重复的客观标准,以及1类克隆,2类克隆。那是不是说,从今以后,我们在编写代码时,再也不能使用我们的最爱,ctrl c,ctrl v,杜绝一切重复代码。

江湖里的侠客,千辛万苦或者机缘巧合,获得一本武林秘籍,他往往也不能立即成为武林高手,作者愿意,读者也不愿意,不科学吗,更不用说对咱们理工男,凡事讲科学,讲逻辑。小说的男主,在获得武林秘籍后,往往还需要吃点苦,流点汗,打打怪,刷刷经验,在女主的照顾下,武力值慢慢提升,还不被别人发现。最后,男主在合适的场合,扮猪吃老虎,大*四方,风光无限,最后抱得美人归,归隐江湖,成为武林神话。咱们码农也一样,deadline是第一位的,先编码,再重构,不断提升技巧,刷经验,历经挫折,成为一代技术牛人。

重构之前类图

接口及类

CheckingAccount:支票账户

SavingsAccount:储蓄账户

Accounts:账户工具类

Transfer:转账类

CheckingAccount:支票账户

makeTransfer()方法,实现支票账户的转账功能,里面有三个步骤,我们重点关注第二步,对账户进行合法性校验。这段代码,将来会发生重复。

package eu.sig.training.ch04.v1; import eu.sig.training.ch04.BusinessException; import eu.sig.training.ch04.Money; // tag::CheckingAccount[] public class CheckingAccount { private int transferLimit = 100; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Check withdrawal limit: if (amount.greaterThan(this.transferLimit)) { throw new BusinessException("Limit exceeded!"); } // 2. Assuming result is 9-digit bank account number, validate 11-test: int sum = 0; for (int i = 0; i < counterAccount.length(); i ) { sum = sum (9-i) * Character.getNumericValue( counterAccount.charAt(i)); } if (sum % 11 == 0) { // 3. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); return result; } else { throw new BusinessException("Invalid account number!"); } } } // end::CheckingAccount[]SavingsAccount:储蓄账户

这个项目,本来只有一个CheckingAccount:支票账户,随着业务的发展,新增了一类新的账户,储蓄账户,程序员为了简单,直接复制CheckingAccount类的代码,修改之后,就成了现在的样子。

它里面也需要有转账功能,但是转账没有限额,但是也需要对账户进行校验,这段代码在CheckingAccount类里面,已经存在,所以这里发生了重复,需要进行重构。

package eu.sig.training.ch04.v1; import eu.sig.training.ch04.BusinessException; import eu.sig.training.ch04.Money; // tag::SavingsAccount[] public class SavingsAccount { CheckingAccount registeredCounterAccount; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Assuming result is 9-digit bank account number, validate 11-test: int sum = 0; // <1> for (int i = 0; i < counterAccount.length(); i ) { sum = sum (9 - i) * Character.getNumericValue( counterAccount.charAt(i)); } if (sum % 11 == 0) { // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // <2> // 3. Check whether withdrawal is to registered counter account: if (result.getCounterAccount().equals(this.registeredCounterAccount)) { return result; } else { throw new BusinessException("Counter-account not registered!"); } } else { throw new BusinessException("Invalid account number!!"); } } } // end::SavingsAccount[]Accounts:账户工具类

package eu.sig.training.ch04.v1; public class Accounts { @SuppressWarnings("unused") public static CheckingAccount findAcctByNumber(String number) { return new CheckingAccount(); } }Transfer:转账类

package eu.sig.training.ch04.v1; import eu.sig.training.ch04.Money; public class Transfer { CheckingAccount counterAccount; @SuppressWarnings("unused") public Transfer(CheckingAccount acct1, CheckingAccount acct2, Money m) {} @SuppressWarnings("unused") public Transfer(SavingsAccount acct1, CheckingAccount acct2, Money m) {} public CheckingAccount getCounterAccount() { return this.counterAccount; } }重构方法-提取方法

上面的CheckingAccount:支票账户 和 SavingsAccount:储蓄账户,都有转账功能,转账时都需要进行账户合法性校验,代码发生重复,可以通过前面我们已经分享的重构技巧-提取方法,将重复的代码提取到Accounts类中。

重构之后

将上面两个方法中的重复代码,提取到Accounts类中,命名为isValid(),为了方便使用,新提取的方法,常常采用static,也就是静态方法。

Accounts:账户工具类

package eu.sig.training.ch04.v2; public class Accounts { @SuppressWarnings("unused") public static CheckingAccount findAcctByNumber(String number) { return new CheckingAccount(); } // tag::isValid[] public static boolean isValid(String number) { int sum = 0; for (int i = 0; i < number.length(); i ) { sum = sum (9 - i) * Character.getNumericValue(number.charAt(i)); } return sum % 11 == 0; } // end::isValid[] }CheckingAccount:支票账户

package eu.sig.training.ch04.v2; import eu.sig.training.ch04.BusinessException; import eu.sig.training.ch04.Money; // tag::CheckingAccount[] public class CheckingAccount { private int transferLimit = 100; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Check withdrawal limit: if (amount.greaterThan(this.transferLimit)) { throw new BusinessException("Limit exceeded!"); } if (Accounts.isValid(counterAccount)) { // <1> // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // <2> return result; } else { throw new BusinessException("Invalid account number!"); } } } // end::CheckingAccount[]SavingsAccount:储蓄账户

package eu.sig.training.ch04.v2; import eu.sig.training.ch04.BusinessException; import eu.sig.training.ch04.Money; // tag::SavingsAccount[] public class SavingsAccount { CheckingAccount registeredCounterAccount; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Assuming result is 9-digit bank account number, // validate with 11-test: if (Accounts.isValid(counterAccount)) { // <1> // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // <2> if (result.getCounterAccount().equals(this.registeredCounterAccount)) { return result; } else { throw new BusinessException("Counter-account not registered!"); } } else { throw new BusinessException("Invalid account number!!"); } } } // end::SavingsAccount[]点评

提取方法,可以消除重复的代码,而且往往为了方便快捷,提取为静态方法,这种方式的弊端,就是有可能会造成另外一个极端。形成了包含大量静态方法,方法与方法之间又没有内在联系的大杂烩工具类。从而导致这个工具类,体积膨胀,并且耦合紧密,因为其他大量的类,都依赖这个类。这是另外一种不良现象,如何预防,或者消除新出现的问题,在本书的第6章,分离模块的关注点(Separate Concerns in Modules)这一原则中,将会进行讲解。

关于提取方法,消除重复代码,今天我们就聊到这里,下期我们聊一个新的重构技巧,提取父类,来消除重复代码。

极客架构师,专注架构师成长,我们下期见。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved