隐藏更多

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

旧版本

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. DEV SIT UAT PET SIM PRD PROD常见环境英文缩写含义

    英文缩写 英文 中文 DEV development 开发 SIT System Integrate Test 系统整合测试(内测) UAT User Acceptance Test 用户验收测试 P ...

  2. linux目录2

    19.linux注释多行 20.防火墙 21.创建逻辑卷 22.两台主机,ssh端口不同,如何拷贝文件    

  3. P1354 房间最短路问题

    传送门 可以发现,最短路一定要经过墙壁的断点. 那么把房间看作一个有向图,墙壁的断点为节点,求从起点到终点的最短路. 这道题的难点在于建图.枚举所有的断点,若可以走则加入这条边. 判断两点是否连通,即 ...

  4. 聊聊计算机中的编码(Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等)以及乱码问题的解决办法

    作为一个程序员,一个中国的程序员,想来“乱码”问题基本上都遇到过,也为之头疼过.出现乱码问题的根本原因是编码与解码使用了不同而且不兼容的“标准”,在国内一般出现在中文的编解码过程中. 我们平时常见的编 ...

  5. SpringBoot整合Sqlite数据库流程

    1.创建项目 方式一: 通过网站https://start.spring.io/ 方式二: 通过开发工具(IDEA或者Eclipse自行百度) 2.修改pom.xml配置文件,添加必要的驱动包 < ...

  6. 如何给CentOS 安装Vmware Tools

    1.打开电脑中的VMware  Workstation 软件,并启动安装了CentOS6.9系统的虚拟机         2.点击“”other”,在Username中输入root,在Password ...

  7. AI佳作解读系列(二)——目标检测AI算法集杂谈:R-CNN,faster R-CNN,yolo,SSD,yoloV2,yoloV3

    1 引言 深度学习目前已经应用到了各个领域,应用场景大体分为三类:物体识别,目标检测,自然语言处理.本文着重与分析目标检测领域的深度学习方法,对其中的经典模型框架进行深入分析. 目标检测可以理解为是物 ...

  8. linux rzsz(lrzsz)安装

    lrzsz 官网入口:https://ohse.de/uwe/software/lrzsz.html lrzsz是一个unix通信套件提供的X,Y,和ZModem文件传输协议,可以用在windows与 ...

  9. 【数学建模】灰色系统理论II-Verhulst建模-GM(1,N)-GM(2,1)建模

    灰色系统理论中,GM(1,1)建模很常用,但他是有一定适应范围的. GM(1,1)适合于指数规律较强的序列,只能描述单调变化过程.对于具有一定随机波动性的序列,我们考虑使用Verhulst预测模型,或 ...

  10. [BZOJ 2480] [SPOJ 3105] Mod

    Description 已知数 \(a,p,b\),求满足 \(a^x\equiv b\pmod p\) 的最小自然数 \(x\). Input 每个测试文件中最多包含 \(100\) 组测试数据. ...