1.封装条件
当代码中充斥着若干条件判断时,代码的真正意图会迷失于这些条件判断之中。这时我喜欢将条件判断提 取到一个易于读取的属性或方法(如果有参数)中。重构之前的代码如下:
public class RemoteControl
{
private string[] Functions { get; set; }
private string Name { get; set; }
private int CreatedYear { get; set; }
public string PerformCoolFunction(string buttonPressed)
{
// Determine if we are controlling some extra function
// that requires special conditions
if (Functions.Length > 1 && Name == "RCA" &&
CreatedYear > DateTime.Now.Year - 2)
return "doSomething";
}
}
重构之后,代码的可读性更强,意图更明显:
public class RemoteControl
{
private string[] Functions { get; set; }
private string Name { get; set; }
private int CreatedYear { get; set; }
private bool HasExtraFunctions
{
get
{
return Functions.Length > 1 && Name == "RCA" &&
CreatedYear > DateTime.Now.Year - 2;
}
}
public string PerformCoolFunction(string buttonPressed)
{
// Determine if we are controlling some extra function
// that requires special conditions
if (HasExtraFunctions)
return "doSomething";
}
}
2.提取超类
当一个类有很多方法希望将它们“提拔”到基类以供同层次的其他类使用时,会经常使用该重构。下面的 类包含两个方法,我们希望提取这两个方法并允许其他类使用。
public class Dog
{
public void EatFood()
{
// eat some food
}
public void Groom()
{
// perform grooming
}
}
重构之后,我们仅仅将需要的方法转移到了一个新的基类中。这很类似“Pull Up”重构,只是在重构之前, 并不存在基类。
public class Animal
{
public void EatFood()
{
// eat some food
}
public void Groom()
{
// perform grooming
}
}
public class Dog : Animal
{
}
3.将异常替换为条件
我曾无数次面对的一个代码坏味道就是,使用异常来控制程序流程。您可能会看到类似的代码:
public class Microwave
{
private IMicrowaveMotor Motor { get; set; }
public bool Start(object food)
{
bool foodCooked = false;
try
{
Motor.Cook(food);
foodCooked = true;
}
catch (InUseException)
{
foodcooked = false;
}
return foodCooked;
}
}
异常应该仅仅完成自己的本职工作:处理异常行为。大多数情况你都可以将这些代码用恰当的条件判断替 换,并进行恰当的处理。下面的代码可以称之为契约式设计,因为我们在执行具体工作之前明确了 Motor 类的状态,而不是通过异常来进行处理。
public class Microwave
{
private IMicrowaveMotor Motor { get; set; }
public bool Start(object food)
{
if (Motor.IsInUse)
return false;
Motor.Cook(food);
return true;
}
}
4.提取工厂类
在代码中,通常需要一些复杂的对象创建工作,以使这些对象达到一种可以使用的状态。通常情况下,这 种创建不过是新建对象实例,并以我们需要的方式进行工作。但是,有时候这种创建对象的需求会极具增 长,并且混淆了创建对象的原始代码。
这时,工厂类就派上用场了。关于工厂模式更全面的描述可以参考 这里。最复杂的工厂模式是使用抽象工厂创建对象族。而我们只是使用最基本的方式,用一个工厂类创建 一个特殊类的实例。来看下面的代码:
public class PoliceCarController
{
public PoliceCar New(int mileage, bool serviceRequired)
{
PoliceCar policeCar = new PoliceCar();
policeCar.ServiceRequired = serviceRequired;
policeCar.Mileage = mileage;
return policeCar;
}
}
如您所见,New 方法负责创建 PoliceCar 并根据一些外部输入初始化 PoliceCar 的某些属性。对于简单的创建 工作来说,这样做可以从容应对。但是久而久之,创建的工作量越来越大,并且被附加在 controller 类上, 但这并不是 controller 类的职责。这时,我们可以将创建代码提取到一个 Factory 类中去,由该类负责 PoliceCar 实例的创建。
public interface IPoliceCarFactory
{
PoliceCar Create(int mileage, bool serviceRequired);
}
public class PoliceCarFactory : IPoliceCarFactory
{
public PoliceCar Create(int mileage, bool serviceRequired)
{
PoliceCar policeCar = new PoliceCar();
policeCar.ReadForService = serviceRequired;
policeCar.Mileage = mileage;
return policeCar;
}
}
public class PoliceCarController
{
public IPoliceCarFactory PoliceCarFactory { get; set; }
public PoliceCarController(IPoliceCarFactory policeCarFactory)
{
PoliceCarFactory = policeCarFactory;
}
public P