21.去除上帝类
去除上帝类:即一个上帝类(万能类)什么事都能做,都由它做,为了遵循面向对象的单一职责原则,应当将其分解成多个功能单一明确的类。
**eg:**CustomerService类里包含了两种功能,一是下单服务,二是注册服务。
public class CustomerService
{
public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
{
// do work
}
public bool CustomerIsValid(Customer customer, Order order)
{
// do work
}
public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
{
// do work
}
public void Register(Customer customer)
{
// do work
}
public void ForgotPassword(Customer customer)
{
// do work
}
}
重构:分解成注册服务和下单服务
public class CustomerOrderService
{
public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
{
// do work
}
public bool CustomerIsValid(Customer customer, Order order)
{
// do work
}
public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
{
// do work
}
}
public class CustomerRegistrationService
{
public void Register(Customer customer)
{
// do work
}
public void ForgotPassword(Customer customer)
{
// do work
}
}
总结:总结: ”去除上帝类“是我们经常容易造成的,第一是因为简便,看到有一个现成的类,大家都会喜欢把代码往里面写,最后导致越写越大,并且声明功能都有,这样即降低了可读性,也造成了维护的负担。
22.为布尔方法命名
为布尔方法命名:对于一个方法带有大量的bool参数,可以分离出几个默认bool值的方法出来
**eg:**createdAccount方法带有过多的bool方法。
class BankAccount
{
public void createdAccount(Customer cust,boolean withChecking,boolean withStocking,boolean withSaving)
{
// do
}
}
重构:为该方法分解出几个具有默认值的方法
class BankAccount
{
public void createdAccountWithChecking(Customer cust)
{
createdAccount(cust,true,false);
}
public void createdAccountWithCheckingAndStocking(Customer cust)
{
createdAccount(cust,true,true);
}
//底层的方法设为private,不为外部所见
private void createdAccount(Customer cust,boolean withChecking,boolean withStocking,boolean withSaving)
{
// do
}
}
23.去除中间人对象
去除中间人对象:即对没有作用的中间类去掉,让两个类之间直接发生关系。
eg:有些时候在我们的代码会存在一些”幽灵类“,设计模式大师Fowler称它们为“中间人”类,“中间人”类除了调用别的对象之外不做任何事情,所以“中间人”类没有存在的必要,我们可以将它们从代码中删除,从而让交互的两个类直接关联。
如下代码所示,Consumer 类要得到AccountDataProvider 的数据,但中间介入了没起任何作用的 AccountManager 类来关联,所以我们应当移除。
public class Consumer
{
public AccountManager AccountManager { get; set; }
public Consumer(AccountManager accountManager)
{
AccountManager = accountManager;
}
public void Get(int id)
{
Account account = AccountManager.GetAccount(id);
}
}
public class AccountManager
{
public AccountDataProvider DataProvider { get; set; }
public AccountManager(AccountDataProvider dataProvider)
{
DataProvider = dataProvider;
}
public Account GetAccount(int id)
{
return DataProvider.GetAccount(id);
}
}
public class AccountDataProvider
{
public Account GetAccount(int id)
{
// get account
}
}
**重构:**Consumer 和AccountDataProvider 直接进行关联,这样代码就简单了。
public class Consumer
{
public AccountDataProvider AccountDataProvider { get; set; }
public Consumer(AccountDataProvider dataProvider)
{
AccountDataProvider = dataProvider;
}
public void Get(int id)
{
Account account = AccountDataProvider.GetAccount(id);
}
}
public class AccountDataProvider
{
public Account GetAccount(int id)
{
// get account
}
}
总结: ”去除中间人对象“很多时候都会很有作用,尤其是在误用设计模式的代码中最容易见到,设计模式中的适配器模式和代理模式等都用中间的类是两者进行关联,这是比较合理的,因为中间类做了很多事情,而对于没有任何作用的中间类应该移除。
24.尽快返回
尽快返回:这是指对于简单的,特殊的情况优先并尽快返回。
eg:
public class Order
{
public Customer Customer { get; private set; }
public decimal CalculateOrder(Customer customer, IEnumerable<Product> products, decimal discounts)
{
Customer = customer;
decimal orderTotal = 0m;
if (products.Count() > 0)
{
orderTotal = products.Sum(p => p.Price);
if (discounts > 0)
{
orderTotal -= discounts;
}
}
return orderTotal;
}
}
重构:对特殊的,简单的情况尽快返回,无需继续下去,比如参数为“0”/“false”的特殊情况。
public class Order
{
public Customer Customer { get; private set; }
public decimal CalculateOrder(Customer customer, IEnumerable<Product> products, decimal discounts)
{
if (products.Count() == 0)
return 0;
Customer = customer;
decimal orderTotal = products.Sum(p => p.Price);
if (discounts == 0)
return orderTotal;
orderTotal -= discounts;
return orderTotal;
}
}
总结:这个重构很重要,它和前面讲的”分解复杂判断“有些类似,我们在做复杂的处理过程时,要经常考虑这个重构,用好了它,会对我们的帮助很大。
25.使用多态代替条件判断
使用多态代替条件判断:当一个类内部需要根据不同类型的类而采取不同的策略时,我们可以将这些不同的策略封装到不同类型的类中,再有统一的一个抽象的接口调用这些不同的策略。
eg:
//客户类:需要支付消费金额
class Customer
{
String type;
String name;
double fee;
public Customer(String type, String name, double fee) {
super();
this.type = type;
this.name = name;
this.fee = fee;
}
}
//收银台:根据不同的客户类型(Vip或Normal)支付不同的消费金额。
class CounterFee
{
public double paidFee(Customer cust)
{
double fee=0;
if(cust.fee==0)
return 0;
if(cust.type.equals("Vip"))
return cust.fee*0.5;
else if(cust.type.equals("Normal"))
return cust.fee*0.9;
return fee;
}
}
重构:
//抽象客户类:需要支付消费金额
abstract class AbsCustomer
{
String type;
String name;
double fee;
public AbsCustomer(String type, String name, double fee) {
this.type = type;
this.name = name;
this.fee = fee;
}
abstract double getFee();
}
//Vip客户类
class VipCustomer extends AbsCustomer
{
public VipCustomer(String type, String name, double fee) {
super(type, name, fee);
// TODO Auto-generated constructor stub
}
@Override
double getFee() {
// TODO Auto-generated method stub
return fee*0.5;
}
}
//普通客户类
class NormalCustomer extends AbsCustomer
{
public NormalCustomer(String type, String name, double fee) {
super(type, name, fee);
// TODO Auto-generated constructor stub
}
@Override
double getFee() {
// TODO Auto-generated method stub
return fee*0.9;
}
}
//收银台:根据不同的客户类型(Vip或Normal)支付不同的消费金额。
class CounterFee
{
public double paidFee(AbsCustomer cust)
{
return cust.getFee();
}
/* public double paidFee(Customer cust)
{
double fee=0;
if(cust.fee==0)
return 0;
if(cust.type.equals("Vip"))
return cust.fee*0.5;
else if(cust.type.equals("Normal"))
return cust.fee*0.9;
return fee;
}*/
}
总结:多态可以省去累赘不清晰的条件判断,增强可读性,维护性。