隐藏更多

只暴露集合中供人使用的单一功能,将关于集合的更多功能隐藏掉。

旧版本

public class Animal
{
    private List<string> LanguageList = new List<string>
    {
        "#$%^",
        "@*&#",
        "中文",
        "英文"
    };

public IList<string> GetLanguageList( )
    {
        return LanguageList;
    }
}

public class Programe
{
    static void Main( string[] args )
    {
        Animal a = new Animal( );
        var language = a.GetLanguageList( );
        language[0]=
    }
}

IList<T>具有索引器,可以通过数组检索的方式设置元素的值,而我们只想让用户调用枚举器对集合进行简单的迭代或查询,但并不需要他们插手对集合元素的值的更改。所以此时就要考虑让GetLanguageList方法返回一个IEnumerable<T>,由于IEnumerable<T>只有一个GetEnumerator的方法,它没有索引器,所以它只能提供一个枚举器供用户调用,从而防止了集合元素被修改的可能。

新版本

public IEnumerable<string> GetLanguageList( ) 
{
    return LanguageList; //方法返回的LanguageList隐式转换为了IEnumerable<string>
}

提升成员

将完全重名的字段、属性、方法提升到基类,供每个子类调用。

聚合模拟多继承

为了使没有逻辑上的继承关系的两个类强行发生关系,可以将其中一个类作为另一个类的成员来存取。

抽象解耦

如果其它类需要与某个类(x)发生关系,则可以将x类抽象成一个接口,将其成员抽象到接口中,其它类只需要和接口发生关系,而不需要直接与x发生关系,好处在于如果今后删除了x,我们还可以创建y类来实现接口,这样就不会影响与接口发生关系的那些类。接口就像角色那样,x具有这个角色所要求的的功能,所以x=此角色,y具有这个角色所要求的的功能,那么y也=此角色,对于其它想要与x发生 关系的那些类来说,它们完全可以只需要与角色发生关系,而不用在乎这个角色是由谁来扮演,所以如果x后来死掉了,它们是不用感到惊慌失措的,因为它们只关心和其发生关系的角色。

用属性替代字段

关键思路:多使用属性,少用字段。因为字段过于粗略,而属性由于多了两个方法块,就可以提供更精细的操作逻辑,在设置或获取数据之前你就可以编码出更多的细节控制。

常量封装

如果一些频繁使用的常量总是存在于方法的代码块中,假如有100个方法都在使用这些常量,而今后需求变更,需要更改这个常量值,你就需要把存在于100个方法中的这个常量值给修改掉,工作量巨大而且毫无乐趣,简单的办法就是,将这种普遍存在于各个方法中的常量封装成一个方法的返回值抑或封装到枚举中以应对将来可能发生的需求变更,需求变更时,只需要在封装的方法里或枚举中修改这个常量值即可。

方法分割

如果一个方法中的逻辑代码过于臃肿,就很难让人去尝试阅读,也不方便调试,更不利于需求变更时的代码修改,方法应该作为一个单一的功能供其它方法调用,所以,将一个有N个操作逻辑的方法分割成多个方法,每个方法只提供一个单一的功能,这样就更便于阅读、理解和修改。

封装条件

如果一个条件判断中有多个条件,这会使代码难以阅读,将条件的逻辑判断封装成望文即可生义的属性或方法后,只需要使用属性或方法做判断即可。如果条件需要用某个参数做判断则把判断的逻辑定义成方法,否则定义成属性即可。

旧版

public class Test
{
    public void Show( string arg )
    {
        if (arg.Trim( new char[] { 'u', 'p' } ).Length > 10 && arg.Contains( "s" ) && arg.LastIndexOf( "a" ) != -1) { }
        if (DateTime.Now.Hour == 12 && DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.DayOfYear == 1984) { }
    }
}

新版

public class Test
{
    public bool IsArgPass( string arg ) { return arg.Trim( new char[] { 'u', 'p' } ).Length > 10 && arg.Contains( "s" ) && arg.LastIndexOf( "a" ) != -1; }
    public bool IsNowTimePass { get { return DateTime.Now.Hour == 12 && DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.DayOfYear == 1984; } }
    public void Show( string arg )
    {
        //望文生义,IsArgPass表示参数是否通过测试
        if (IsArgPass( arg )) { }
        //望文生义,IsDatimePass表示当前时间是否正确
        if (IsNowTimePass) { }
    }
}

移除条件

如果一个类需要根据条件调用不同的方法,假如有100个条件就需要判断100次。这样就降低了代码的复用性和灵活性。为此,可以使用一个简单的策略,将条件作为哈希字典的key,将对应的方法作为哈希字典的Value,当用户传递一个条件到类中,类只需要从哈希字典去取出Key所对应方法即可。

旧版本

//国籍
public enum Country { UnitedKingdom = 1 << 1, Japan = 1 << 2, China = 1 << 3 }

//语言
public class Language
{
    public void UnitedKingdomLanguage() { Console.WriteLine( "hello" ); }
    public void JapanLanguage( ) { Console.WriteLine( "ハロー" ); }
    public void ChinaLanguage( ) { Console.WriteLine( "你好" ); }
}

//服务
public class Service
{
    private Language Language = new Language( );
    //根据国籍提供不同版本的语言对话
    public void ShowLanguage( Country country )
    {
        switch (country)
        {
            case Country.Japan:
                Language.JapanLanguage( );
                break;
            case Country.China:
                Language.ChinaLanguage( );
                break;
            case Country.UnitedKingdom:
                Language.UnitedKingdomLanguage( );
                break;
        }
    }
}

Service service = new Service( );
service.ShowLanguage( Country.Japan );

新版本

//国籍
public enum Country { UnitedKingdom = 1 << 1, Japan = 1 << 2, China = 1 << 3 }

//语言接口
public interface ILanguage
{
    void UnitedKingdomLanguage( );
    void JapanLanguage( );
    void ChinaLanguage( );
}

//语言
public class Language:ILanguage
{
    public void UnitedKingdomLanguage() { Console.WriteLine( "hello" ); }
    public void JapanLanguage( ) { Console.WriteLine( "ハロー" ); }
    public void ChinaLanguage( ) { Console.WriteLine( "你好" ); }
}

//服务
public class Service
{
    private ILanguage Language;
    private Dictionary<Country,Action> LanguageMethodDictionary { get; set; }
    public Service( ILanguage language )
    {
        this.Language = language;
        LanguageMethodDictionary = new Dictionary<Country, Action>
        {
            { Country.China, Language.ChinaLanguage },
            { Country.Japan, Language.JapanLanguage },
            { Country.UnitedKingdom, Language.UnitedKingdomLanguage },
        };
    }
     
    //根据国籍提供不同版本的语言对话
    public void ShowLanguage( Country country )
    {
        LanguageMethodDictionary[country]( );
    }
}

Service service = new Service( new Language() );
service.ShowLanguage( Country.Japan );

尽早返回

如果一个方法中有大量的条件分支语句,这会使得整个逻辑走向变得不清晰,最佳做法是尽早return,把不满足条件的情况尽早返回,这样可以使代码更容易理解和阅读。

  

  

C# - 学习总目录

C# - 代码重构的更多相关文章

  1. 让代码重构渐行渐远系列(3)——string.Equals取代直接比较与非比较

    重构背景及原因 最近由于项目组的人员在不断扩充,导致项目中代码风格各异,大有百花齐放甚至怒放之势.考虑到团队的生存与发展,经过众人多次舌战之后,最终决定项目组根据业务分成几个小分队,以加强团队管理与提 ...

  2. C++代码重构——从C global到C++ template

    在学数据结构的时候,我常有这样目标--写出能够最大程度复用的代码(算法正确,封装优秀).我常想--如何能在短时间内达成"算法正确,封装优秀"这样的目标.经过一段时间的摸索,我的结论 ...

  3. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...

  4. CSS代码重构与优化之路

    作者:@狼狼的蓝胖子 网址:http://www.cnblogs.com/lrzw32/p/5100745.html 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多, ...

  5. NET代码重构

    记一次.NET代码重构   好久没写代码了,终于好不容易接到了开发任务,一看时间还挺充足的,我就慢慢整吧,若是遇上赶进度,基本上直接是功能优先,完全不考虑设计.你可以认为我完全没有追求,当身后有鞭子使 ...

  6. 代码重构 & 常用设计模式

    代码重构 重构目的 相同的代码最好只出现一次 主次方法 主方法 只包含实现完整逻辑的子方法 思维清楚,便于阅读 次方法 实现具体逻辑功能 测试通过后,后续几乎不用维护 重构的步骤 1  新建一个方法 ...

  7. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十一) 代码重构使用反射工厂解耦

    前言 自从此博客发表以及代码开源以来,得到了许多人的关注.也没许多吧,反正在我意料之外的.包括几位大牛帮我做订阅号推广,真的很感谢他们.另外,还有几个高手给我提了一些架构上的问题.其实本身这个项目是没 ...

  8. CSS代码重构

    CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS代码重构主要有两个目的:1.提高代码性能2.提高代码的可维护性 提高代码性能 提高 ...

  9. 多线程的练习----妖,等待唤醒,代码重构,lock到condition

    × 目录 [1]需求 [2]妖的出现和解决 [3]等待唤醒 [4]代码重构 [5]改成Lock Condition ------------------------------------- 1,需求 ...

  10. 推荐五款优秀的PHP代码重构工具

    在软件工程学里,重构代码一词通常是指在不改变代码的外部行为情况下而修改源代码.软件重构需要借助工具完成,而重构工具能够修改代码同时修改所有引用该代码的地方.本文收集了五款出色的PHP代码重构工具,以帮 ...

随机推荐

  1. JVM内存溢出时快照转存HeapDump到文件

    # Heap Dump 获取方式使用 JVM 参数获取 dump 文件进入Tomcat的'bin'目录,在'catalina.sh'文件里添加如下内容 >-XX:+HeapDumpOnOutOf ...

  2. 洛谷P4057

    题目描述 “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不过由于种种原因 ...

  3. CF618F Double Knapsack 构造、抽屉原理

    传送门 首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做.考虑加强限制条件:将"选取子集"的限制变为"选取子序列"的限制.在接下来的讨论中我们将会知道: ...

  4. MongoDB小东西

    在mongodb中,show users 和db.system.users.find() 都能查看账户的相关信息,但是这两个命令有什么区别么? db.system.users.find() 是查看全局 ...

  5. 开发工具IntelliJ IDEA的安装步骤及首次启动和创建项目

    开发工具IDEA概述 DEA是一个专门针对Java的集成开发工具(IDE),由Java语言编写.所以,需要有JRE运行环境并配置好环境变量.它可以极大地提升我们的开发效率.可以自动编译,检查错误.在公 ...

  6. Git—推送代码至Github

    Git—上传代码至Github 首先得有个Github的账户,然后创建一个库. 然后找到指向改库的URL 第一次上传需要设置用户邮箱,打开git安装文件/bin下面找到git.bash并打开,设置全局 ...

  7. Python——递归函数

    1.定义:在自己的函数,调用自己 2.递归的最大内存不能超过997层 import sys sys.setrecursionlimit(1000000)   可以达到电脑理论的最大次 import s ...

  8. Assignment HDU - 2853(求最小改变边数)

    Assignment Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. hihoCoder #1770 : 单调数(数位dp)

    题面 我们定义一个数是单调数,当且仅当构成这个数每一个数位都是单调不降或不增的. 例如 \(123\) 和 \(321\) 和 \(221\) 和 \(111\) 是单调的,而 \(312\) 不是单 ...

  10. webpack学习记录-初步体验(一)

    一.关于webpack 自从出现模块化以后,大家可以将原本一坨代码分离到个个模块中,但是由此引发了一个问题.每个 JS 文件都需要从服务器去拿,由此会导致加载速度变慢.Webpack 最主要的目的就是 ...