1月 25

代码中有很多try…catch的语句,用来处理异常

但是不应该用异常来控制程序流程,异常只应该用来完成本职工作即处理异常的情况

而不是用来控制流程

这个重构就是讲的这个,

旧的代码:

    public class Microwave
     {
        private IMicrowaveMotor Motor { get; set; }
        public bool Start(object food)
         {
            bool foodCooked = false;
            try
             {
                 Motor.Cook(food);
                 foodCooked = true;
             }
            catch (Exception ex)
             {
                 foodcooked = false;
             }
            return foodCooked;
         }
     }

重构后的代码如下:

    public class Microwave
     {
        private IMicrowaveMotor Motor { get; set; }
        public bool Start(object food)
         {
            if (Motor.IsInUse)
                return false;
             Motor.Cook(food);
            return true;
         }
     }

written by ocean

1月 25

今天的重构其实和 第3天:上移方法 非常相似

也就是把一些常用的方法放在一个基类里,这样其它类可以直接调用该方法,而不用重新实现或者引用

其实我各人感觉两者是一样的意思,呵呵

旧的代码:

    public class Dog
     {
        public void EatFood()
         {
            // eat some food
         }
        public void Groom()
         {
            // perform grooming
         }
     }

重构后代码:

    public class Animal
     {
        public void EatFood()
         {
            // eat some food
         }
        public void Groom()
         {
            // perform grooming
         }
     }
    public class Dog : Animal
     {
     }

这个还是很实用的,比方说公司的程序吧

    protected string GetGBSubstring(string originalString, int length)

这个就放在基类中,使用起来很方便

written by ocean

1月 25

今天这个重构比较不错,将代码中充斥的N多判断条件提取成为一个属性,可以实现复用,并且使得结构清晰

旧的代码:

    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”;
            return “Other”;
         }
     }

重构成如下模样:

    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”;
         }
     }

重构后代码结构更加清晰,这个重构我比较喜欢

written by ocean

1月 24

这个重构应该是最常见的,并且在我们开发中就应该注意避免,也就是copy代码,相同的代码内容在项目不同的地方出现多次,确实应该消除。下次如果要Copy代码的时候抽取出来一个公共的方法来调用吧

例子很简单,就不多说了,直接上代码

旧代码

    public class MedicalRecord
     {
        public DateTime DateArchived { get; private set; }
        public bool Archived { get; private set; }
        public void ArchiveRecord()
         {
             Archived = true;
             DateArchived = DateTime.Now;
         }
        public void CloseRecord()
         {
             Archived = true;
             DateArchived = DateTime.Now;
         }
     }

重构后的代码:

    public class MedicalRecord
     {
        public DateTime DateArchived { get; private set; }
        public bool Archived { get; private set; }
        public void ArchiveRecord()
         {
            //DoSomeThing1
             SwitchToArchived();
         }
        public void CloseRecord()
         {
            //DoSomeThing2
             SwitchToArchived();
         }
        private void SwitchToArchived()
         {
             Archived = true;
             DateArchived = DateTime.Now;
         }
     }

written by ocean

1月 24

Break Responsibilities,想了半天,改为拆分职责

今天这个重构主要是讲的单一职责方面的 ,旧代码如下

    public class Video
     {
        public void PayFee(decimal fee)
         {
         }
        public void RentVideo(Video video, Customer customer)
         {
             customer.Videos.Add(video);
         }
        public decimal CalculateBalance(Customer customer)
         {
            return customer.LateFees.Sum();
         }
     }

出租碟片和顾客管理都放在一个类里面,结构不够清晰,要进行拆分,重构后代码如下

    public class Video
     {
        public void RentVideo(Video video, Customer customer)
         {
             customer.Videos.Add(video);
         }
     }
    public class Customer
     {
        public IList<decimal> LateFees { get; set; }
        public IList Videos { get; set; }
        public void PayFee(decimal fee)
         {
         }
        public decimal CalculateBalance(Customer customer)
         {
            return customer.LateFees.Sum();
         }
     }

written by ocean

1月 21

ICloneable 接口包含一个成员 Clone,它用于支持除 MemberwiseClone 所提供的克隆之外的克隆。

实现接口:

    public class AddressInfo : ICloneable
     {
        public AddressInfo(string userName, string phone)
         {
            this.UserName = userName;
            this.Phone = phone;
         }
        public string UserName { get; set; }
        public string Phone { get; set; }

        public override string ToString()
         {
            return string.Format("姓名:{0},电话:{1}", this.UserName, this.Phone);
         }

        public object Clone()
         {
             AddressInfo addressInfo = new AddressInfo(this.UserName, this.Phone);
            return addressInfo;
         }
     }

调用接口:

             AddressInfo ad1 = new AddressInfo("小李", "123456789");
             AddressInfo ad2 = ad1;
             AddressInfo ad3 = ad1.Clone() as AddressInfo;

             ad2.UserName = "小李的相等";
             ad3.UserName = "小李的克隆";

             Console.WriteLine(ad1.ToString());
             Console.WriteLine(ad2.ToString());
             Console.WriteLine(ad3.ToString());

             Console.Read();

结果:

written by ocean

1月 21

这个重构建议是对第10天:提取方法的继续

我们在一个类中提取出来了大量的私有方法和变量,会造成这个类臃肿不堪,难以阅读

因此最好提取出来方法对象,用以将功能的一个个逻辑分离开

旧的代码:

    public class OrderInfo
     {
        public decimal Price { get; private set; }
     }
    public class Order
     {
        private IList OrderLineItems { get; set; }
        private IList<decimal> Discounts { get; set; }
        private decimal Tax { get; set; }
        public decimal Calculate()
         {
            decimal subTotal = 0m;
            // Total up line items
            foreach (OrderInfo lineItem in OrderLineItems)
             {
                 subTotal += lineItem.Price;
             }
            // Subtract Discounts
            foreach (decimal discount in Discounts)
                 subTotal -= discount;
            // Calculate Tax
            decimal tax = subTotal * Tax;
            // Calculate GrandTotal
            decimal grandTotal = subTotal + tax;
            return grandTotal;
         }
     }

重构后的代码,我们通过构造方法,将返回计算结果的类的引用传递给包含多个计算方法的新建对象,或者向方法对象的构造函数中单独传递各个参数。

    public class OrderInfo
     {
        public decimal Price { get; private set; }
     }
    public class Order
     {
        public IEnumerable OrderLineItems { get; private set; }
        public IEnumerable<decimal> Discounts { get; private set; }
        public decimal Tax { get; private set; }
        public decimal Calculate()
         {
            return new OrderCalculator(this).Calculate();
         }
     }
    public class OrderCalculator
     {
        private decimal SubTotal { get; set; }
        private IEnumerable OrderLineItems { get; set; }
        private IEnumerable<decimal> Discounts { get; set; }
        private decimal Tax { get; set; }
        public OrderCalculator(Order order)
         {
             OrderLineItems = order.OrderLineItems;
             Discounts = order.Discounts;
             Tax = order.Tax;
         }
        public decimal Calculate()
         {
             CalculateSubTotal();
             SubtractDiscounts();
             CalculateTax();
            return SubTotal;
         }
        private void CalculateSubTotal()
         {
            // Total up line items
            foreach (OrderInfo lineItem in OrderLineItems)
                 SubTotal += lineItem.Price;
         }
        private void SubtractDiscounts()
         {
            // Subtract Discounts
            foreach (decimal discount in Discounts)
                 SubTotal -= discount;
         }
        private void CalculateTax()
         {
            // Calculate Tax
             SubTotal += SubTotal * Tax;
         }
     }

written by ocean

1月 21

今天的重构我觉得没有太大用处

旧的代码

    public class AnimalFeedingService
     {
        private bool FoodBowlEmpty { get; set; }
        public void Feed()
         {
            if (FoodBowlEmpty)
                 Feeder.ReplenishFood();
            // more code to feed the animal
         }
     }
    public static class Feeder
     {
        public static void ReplenishFood()
         {
            // fill up bowl
         }
     }

重构后的代码:

    public class AnimalFeedingService
     {
        public IFeederService FeederService { get; set; }
        public AnimalFeedingService(IFeederService feederService)
         {
             FeederService = feederService;
         }
        private bool FoodBowlEmpty { get; set; }
        public void Feed()
         {
            if (FoodBowlEmpty)
                 FeederService.ReplenishFood();
            // more code to feed the animal
         }
     }
    public interface IFeederService
     {
        void ReplenishFood();
     }
    public class FeederService : IFeederService
     {
        public void ReplenishFood()
         {
             Feeder.ReplenishFood();
         }
     }
    public static class Feeder
     {
        public static void ReplenishFood()
         {
            // fill up bowl
         }
     }

该重构主要用来单元测试时模拟静态类

written by ocean

1月 21

今天的重构很有意思,旧的代码是根据参数State来调用三个不同的方法,获取三个地方的装运量

代码如下:

    public class ClientCode
     {
        public decimal CalculateShipping()
         {
             ShippingInfo shippingInfo = new ShippingInfo();
            return shippingInfo.CalculateShippingAmount(State.Alaska);
         }
     }
    public enum State
     {
         Alaska,
         NewYork,
         Florida
     }
    public class ShippingInfo
     {
        public decimal CalculateShippingAmount(State shipToState)
         {
            switch (shipToState)
             {
                case State.Alaska:
                    return GetAlaskaShippingAmount();
                case State.NewYork:
                    return GetNewYorkShippingAmount();
                case State.Florida:
                    return GetFloridaShippingAmount();
                default:
                    return 0m;
             }
         }
        private decimal GetAlaskaShippingAmount()
         {
            return 15m;
         }
        private decimal GetNewYorkShippingAmount()
         {
            return 10m;
         }
        private decimal GetFloridaShippingAmount()
         {
            return 3m;
         }
     }

如果我们现在要加一个Chicago的条件,那么不得不修改整个ShippingInfo

重构后用策略模式,对每一个条件加一个类,并且实现同一个接口,以后如果希望添加新的条件,只需添加新的实现类就可以了,实现对修改关闭,对扩展开放

重构后的代码如下

    public class ClientCode
     {
        public decimal CalculateShipping()
         {
             ShippingInfo shippingInfo = new ShippingInfo();
            return shippingInfo.CalculateShippingAmount(State.Alaska);
         }
     }
    public enum State
     {
         Alaska,
         NewYork,
         Florida
     }
    public class ShippingInfo
     {
        private IDictionary ShippingCalculations
         { get; set; }
        public ShippingInfo()
         {
             ShippingCalculations = new Dictionary{
                                         { State.Alaska, new AlaskShippingCalculation() },
                                         { State.NewYork, new NewYorkShippingCalculation() },
                                         { State.Florida, new FloridaShippingCalculation() }};
         }
        public decimal CalculateShippingAmount(State shipToState)
         {
            return ShippingCalculations[shipToState].Calculate();
         }
     }

    public interface IShippingCalculation
     {
        decimal Calculate();
     }
    public class AlaskShippingCalculation : IShippingCalculation
     {
        public decimal Calculate()
         {
            return 15m;
         }
     }
    public class NewYorkShippingCalculation : IShippingCalculation
     {
        public decimal Calculate()
         {
            return 10m;
         }
     }
    public class FloridaShippingCalculation : IShippingCalculation
     {
        public decimal Calculate()
         {
            return 3m;
         }
     }

故事还没完,书的作者又进行了如下的重构,今天没有弄明白,先记录下来

    public interface IShippingInfo
     {
        decimal CalculateShippingAmount(State state);
     }
    public class ClientCode
     {
         [Inject]
        public IShippingInfo ShippingInfo { get; set; }
        public decimal CalculateShipping()
         {
            return ShippingInfo.CalculateShippingAmount(State.Alaska);
         }
     }
    public enum State
     {
         Alaska,
         NewYork,
         Florida
     }
    public class ShippingInfo : IShippingInfo
     {
        private IDictionary ShippingCalculations
         { get; set; }

        public ShippingInfo(IEnumerable shippingCalculations)
         {
             ShippingCalculations = shippingCalculations.ToDictionary(
             calc => calc.State);
         }
        public decimal CalculateShippingAmount(State shipToState)
         {
            return ShippingCalculations[shipToState].Calculate();
         }
     }
    public interface IShippingCalculation
     {
         State State { get; }
        decimal Calculate();
     }

    public class AlaskShippingCalculation : IShippingCalculation
     {
        public State State { get { return State.Alaska; } }
        public decimal Calculate()
         {
            return 15m;
         }
     }
    public class NewYorkShippingCalculation : IShippingCalculation
     {
        public State State { get { return State.NewYork; } }
        public decimal Calculate()
         {
            return 10m;
         }
     }
    public class FloridaShippingCalculation : IShippingCalculation
     {
        public State State { get { return State.Florida; } }
        public decimal Calculate()
         {
            return 3m;
         }
     }

written by ocean

1月 21

这一条重构的建议是尽量提取方法,使得代码更加清晰明了

旧的代码:

    public class Receipt
     {
        private IList<decimal> Discounts { get; set; }
        private IList<decimal> ItemTotals { get; set; }
        public decimal CalculateGrandTotal()
         {
            decimal subTotal = 0m;
            foreach (decimal itemTotal in ItemTotals)
                 subTotal += itemTotal;
            if (Discounts.Count > 0)
             {
                foreach (decimal discount in Discounts)
                     subTotal -= discount;
             }
            decimal tax = subTotal * 0.065m;
             subTotal += tax;
            return subTotal;
         }
     }

为了弄明白CalculateGrandTotal() 这个方法的意思你会把代码整个看一遍,从而知道是做了3件事情

1,计算总额

2,计算优惠折扣

3,添加消费税

相比较而言我们可以作如下重构

    public class Receipt
     {
        private IList<decimal> Discounts { get; set; }
        private IList<decimal> ItemTotals { get; set; }
        public decimal CalculateGrandTotal()
         {
            decimal subTotal = CalculateSubTotal();
             subTotal = CalculateDiscounts(subTotal);
             subTotal = CalculateTax(subTotal);
            return subTotal;
         }
        private decimal CalculateTax(decimal subTotal)
         {
            decimal tax = subTotal * 0.065m;
             subTotal += tax;
            return subTotal;
         }
        private decimal CalculateDiscounts(decimal subTotal)
         {
            if (Discounts.Count > 0)
             {
                foreach (decimal discount in Discounts)
                     subTotal -= discount;
             }
            return subTotal;
         }
        private decimal CalculateSubTotal()
         {
            decimal subTotal = 0m;
            foreach (decimal itemTotal in ItemTotals)
                 subTotal += itemTotal;
            return subTotal;
         }
     }

将三件事情分成三个子方法,这样每个方法可以专司其职,使得代码更具有可读性

这是一个很重要的重构方法,方法尽量不要超过100行,因为越长的方法越容易出bug

written by ocean