前言
有些开发者在编写方法时,可能较少地去思考一个问题:方法放在这个class中是否合适?
他们可能会觉得:这个方法已经实现xxx功能了,放在哪个class都一样的,class不就是一个装方法的容器嘛。
我赞同class是一个装东西的容易,且不仅限于方法。但是,容器是有区别的。
生活中我们会用到杯子和箱子,杯子和箱子都是容器。
倘若你用杯子装书,用箱子装水,会产生不好的结果——杯子里放不了书,水装进箱子后,会打湿箱子。
隐藏代码 |
// 杯子public class Cup{ // 装书 public void HoldBook() { }}// 箱子public class Box{ // 装水 public void HoldWater() { }}
按照生活常识,我们应该用杯子装水,用箱子装书。
隐藏代码 |
// 杯子public class Cup{ // 装水 public void HoldWater() { }}// 箱子public class Box{ // 装书 public void HoldBook() { }}
每个开发者在完成功能后,回过头来最读一读自己的代码,是否存在一些“牛头不对马嘴”的方法?至少应该确认方法和class的功能是匹配的。
移动方法
这个前言有些长,现在引入本文的主题:”移动方法“。
当某个类的方法实现的功能更多地适用于另外一个类,且符合它的语义时,应将该方法移动到另外一个类。
该定义中有两个关键点:1. 适用性 2. 语义。”适用性“是指方法实现的功能应该适用它所处的class,”语义“是指方法的所描述的功能和class的语义是一致的。
”语义“的重要性优于”适用性“,一些扩展方法或者帮助类(工具类),它们通常只会被其它class调用。这种情况下,符合“语义”更优先。
例如:有些开发者在编写Excel工具类时,在ExcelUtil中出现了ExportCsv()这样的方法,尽管导出的Csv格式是可以用Excel打开的。
示例
这段代码定义了两个类:BankAccount、AccountInterest,分别表示银行账户和账户利率。请注意,计算利率的方法CalculateInterestRate()
在BankAccount类中。
隐藏代码 |
namespace MoveMethod.Before{ /// <summary> /// 银行账户 /// </summary> public class BankAccount { public BankAccount(int accountAge, int creditScore, AccountInterest accountInterest) { AccountAge = accountAge; CreditScore = creditScore; AccountInterest = accountInterest; } public int AccountAge { get; private set; } public int CreditScore { get; private set; } public AccountInterest AccountInterest { get; private set; } // 计算利率 public double CalculateInterestRate() { if (CreditScore > 800) return 0.02; if (AccountAge > 10) return 0.03; return 0.05; } } /// <summary> /// 账户利率 /// </summary> public class AccountInterest { public BankAccount Account { get; private set; } public AccountInterest(BankAccount account) { Account = account; } public double InterestRate { get { return Account.CalculateInterestRate(); } } public bool IntroductoryRate { get { return Account.CalculateInterestRate() < 0.05; } } }}
咋一看,这两个类没有什么问题,它们已经能够描述一件客观事实——”银行账户信息和账户计算利率的方式“。由于已经定义了AccountInterest类,这个类本身是和利率相关的,所以将CalculateInterestRate()
方法放在BankAccount类中不太合适,应将其移动到AccountInterest类中。
隐藏代码 |
namespace MoveMethod.After{ /// <summary> /// 银行账户 /// </summary> public class BankAccount { public BankAccount(int accountAge, int creditScore, AccountInterest accountInterest) { AccountAge = accountAge; CreditScore = creditScore; AccountInterest = accountInterest; } public int AccountAge { get; private set; } public int CreditScore { get; private set; } public AccountInterest AccountInterest { get; private set; } } /// <summary> /// 账户利率 /// </summary> public class AccountInterest { public BankAccount Account { get; private set; } public AccountInterest(BankAccount account) { Account = account; } public double InterestRate { get { return CalculateInterestRate(); } } public bool IntroductoryRate { get { return CalculateInterestRate() < 0.05; } } /// <summary> /// 计算利率 /// </summary> public double CalculateInterestRate() { if (Account.CreditScore > 800) return 0.02; if (Account.AccountAge > 10) return 0.03; return 0.05; } }}
下图描述了重构前后的区别(蓝色表示重构前,红色表示重构后)
原标题:小酌重构系列[1]移动方法
关键词: