31天重构学习笔记重新整理下载

前言

            前两天写了一篇程序猿也爱学英语(上),有图有真相的文章,写作那篇文章只是自己一时兴起,或者说是自己的兴趣使然。文中的观点只是自己的学习心得和体会,属一家之言且鉴于本人不是学英语出身,所以也肯定有不正确的地方,也欢迎大家积极讨论并给我留言,再次感谢大家的热烈支持。关于大家询问下篇的发布问题,我想我会尽力在周末完成。

            这几天由于刚发布完项目,所以有比较充裕的时间整理自己的知识库,发现三年多以前学习并记录了31天重构系列笔记,至今仍回味无穷,索性重新阅读、纠正错误并重新排版整理出来,希望再次和大家一起分享。

            对31天重构系列文章最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的 blog,所以是在国外的社区上闲逛的时候链接过去的。基于文章中的重构点都比较常用,所以一口气看完了整个系列,同时由于这些重构Tips基本上项目都在使用,只是我们没有专门把它标示和整理出来,所以当时也没有引起多大的重视。

            但就在三年前,当时我们在做一个WPF的重构项目且鉴于团队成员技术和经验参差不齐,非常必要专门整理一个重构的纲要,所以就收集和整理了很多的资料(31天重构也在其中)。当然这个系列除了用语重构Tips之外,也非常适合做新系统的代码规范参考。总而言之:只要有代码的地方,这个重构规范就很有价值。同时鉴于当时自己刚到新加坡这个美丽的城市,没有亲戚或者朋友,周末也不想出去闲逛,所以才静下心来用了足足两天时间学习并写完了这个系列笔记。

            31天重构这个系列和《代码大全》、《重构:改善既有代码的设计》比较起来最大的特点就是比较简单且浅显易懂。我这系列文章也都是学习并概括Sean Chambers的31天重构的知识要领,所以如果大家对这个笔记有任何的问题或者异议也可以指出,或者大家可以直接去看原文(即可掌握了技术,又可以学习英语!):

http://www.lostechies.com/blogs/sean_chambers/archive/2009/07/31/31-days-of-refactoring.aspx

 

代码下载地址:http://github.com/schambers/days-of-refactoring

 

imageimage

目录

1. 封装集合

概念:本文所讲的封装集合就是把集合进行封装,只提供调用端需要的接口。

正文:在很多时候,我们都不希望把一些不必要的操作暴露给调用端,只需要给它所需要的操作或数据就行,那么做法就是封装。这个重构在微软的代码库也经常遇到。比如最经典的属性对字段的封装就是一个很好的例子,那么下面我们将看到对集合的封装,如下代码所示,调用端只需要一个集合的信息,而我们则提供了一个IList的集合,大家都知道IList具有对集合的所有操作,所以这会带来很多隐患,最好的做法就是对它进行重构。

using System.Collections.Generic;

namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.Before
{
    public class Order
    {
        private List<OrderLine> _orderLines;
        private double _orderTotal;

        public IList<OrderLine> OrderLines
        {
            get { return _orderLines; }
        }

        public void AddOrderLine(OrderLine orderLine)
        {
            _orderTotal += orderLine.Total;
            _orderLines.Add(orderLine);
        }

        public void RemoveOrderLine(OrderLine orderLine)
        {
            orderLine = _orderLines.Find(o => o == orderLine);

            if (orderLine == null)
                return;

            _orderTotal -= orderLine.Total;
            _orderLines.Remove(orderLine);
        }
    }

    public class OrderLine
    {
        public double Total { get; private set; }
    }
} 

那么重构之后,我们把IList换成了IEnumerable,大家都知道只包括一个返回值为IEnumerator的GetEnumerator()方法,所以这样只能遍历取出它的值,而不能对这个集合做出改变,这正是我们所需要的结果,具体代码如下:

using System.Collections.Generic;

namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.After
{
    public class Order
    {
        private List<OrderLine> _orderLines;
        private double _orderTotal;

        public IEnumerable<OrderLine> OrderLines
        {
            get { return _orderLines; }
        }

        public void AddOrderLine(OrderLine orderLine)
        {
            _orderTotal += orderLine.Total;
            _orderLines.Add(orderLine);
        }

        public void RemoveOrderLine(OrderLine orderLine)
        {
            orderLine = _orderLines.Find(o => o == orderLine);

            if (orderLine == null)
                return;

            _orderTotal -= orderLine.Total;
            _orderLines.Remove(orderLine);
        }
    }

    public class OrderLine
    {
        public double Total { get; private set; }
    }
}

总结:这个例子很容易让我们想到以前系统间耦合常喜欢用数据库。每个系统都会操作数据库,并且有些系统还会对数据库的表结构或字段进行修改,那么这很容易就会造成维护的地狱,很明智的一个做法就是使用SOA来隔开这些耦合,让一些只需要数据展示的系统得到自己需要的数据即可。

2. 移动方法

概念:本文所讲的移动方法就是方法放在合适的位置(通常指放在合适的类中)。

正文:移动方法是一个很简单也很常见的重构,只要是系统就会存在很多类,那么类里面包括很多方法,如果一个方法经常被另外一个类使用(比本身的类使用还多)或者这个方法本身就不应该放在这个类里面,那么这个适合应该考虑把它移到合适的类中。代码如下:

namespace LosTechies.DaysOfRefactoring.MoveMethod.Before
{
    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;
        }
    }

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

移动以后大家可以看到BankAccount类的职责也单一,同时CalculateInterestRate也放到了经常使用且适合它的类中了,所以此重构是一个比较好的重构,能让整个代码变得更加合理。

namespace LosTechies.DaysOfRefactoring.MoveMethod.After
{
    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; }
        }

        public double CalculateInterestRate()
        {
            if (Account.CreditScore > 800)
                return 0.02;

            if (Account.AccountAge > 10)
                return 0.03;

            return 0.05;
        }
    }
}

 

namespace LosTechies.DaysOfRefactoring.MoveMethod.After
{
    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; }
    }
}

总结:这个重构法则在很多时候能让我们把代码组织的结构调整得更合理,同时也能给以后的维护带来方便。

 

3. 提升方法

概念:提升方法是指将一个很多继承类都要用到的方法提升到基类中。

正文:提升方法是指将一个很多继承类都要用到的方法提升到基类中,这样就能减少代码量,同时让类的结构更清晰。如下代码所示,Turn方法在子类Car Motorcycle 都会用到,因为Vehicle 都会有这个方法,所以我们就会想到把它提到基类中。

namespace LosTechies.DaysOfRefactoring.PullUpMethod.Before
{
    public abstract class Vehicle
    {
        // other methods
    }

    public class Car : Vehicle
    {
        public void Turn(Direction direction)
        {
            // code here
        }
    }

    public class Motorcycle : Vehicle
    {
    }

    public enum Direction
    {
        Left,
        Right
    }
}

重构后的代码如下,那么现在Car Motorcycle 都具有Turn这个方法,如果这个方法修改也只需要修改基类即可,所以给维护和以后的重构带来了方便。

namespace LosTechies.DaysOfRefactoring.PullUpMethod.After
{
    public abstract class Vehicle
    {
        public void Turn(Direction direction)
        {
            // code here
        }
    }

    public class Car : Vehicle
    {
    }

    public class Motorcycle : Vehicle
    {
    }

    public enum Direction
    {
        Left,
        Right
    }
}

总结:这个重构要根据具体情况使用,如果不是每个子类都有这个方法的话,可以考虑使用接口或者其他方式。

 

4. 降低方法

概念:本文中的降低方法和前篇的提升方法整好相反,也就是把个别子类使用到的方法从基类移到子类里面去。

正文:如下代码所示,Animal 类中的方法Bark只有在其子类Dog 中使用,所以最好的方案就是把这个方法移到子类Dog 中。

namespace LosTechies.DaysOfRefactoring.PushDownMethod.Before
{
    public abstract class Animal
    {
        public void Bark()
        {
            // code to bark
        }
    }

    public class Dog : Animal
    {
    }

    public class Cat : Animal
    {
    }
}

重构后的代码如下,同时如果在父类Animal 中如果没有其他的字段或者公用方法的话,可以考虑把Bark方法做成一个接口,从而去掉Animal 类。

namespace LosTechies.DaysOfRefactoring.PushDownMethod.After
{
    public abstract class Animal
    {
    }

    public class Dog : 
  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值