隐藏更多

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

旧版本

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. 10-ajax技术简介

    一.ajax是什么?是网页中的异步刷新技术.其核心是js+xml二.执行过程1.js的核心对象XMLHttpRequest是一个具备像后台发送请求的一个对象2.XMLHttpRequest可以异步发送 ...

  2. Kafka简介、基本原理、执行流程与使用场景

    一.简介 Apache Kafka是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统. 它最初由LinkedIn公司开发,Linkedin于201 ...

  3. 通过Excel生成PowerDesigner表结构设计

    说明:近期做部分表结构设计,在word里设计调整好了,需要整理到PowerDesigner中,但是手工录入太麻烦. 找了个工具(地址:http://www.cnblogs.com/hwaggLee/p ...

  4. 小小知识点(五)——MATLAB对复数的操作

    MATLAB程序 a=3+4*i %复数 real(a) %求复数的实部 imag(a) %求复数的虚部 abs(a) %求复数的模 angle(a) %求复数的相位 conj(a) %求复数的复共轭 ...

  5. 数据库优化-mysql中INNODB和MYIASM引擎的区别

    Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别. 该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQ ...

  6. 【转】CENTOS/RHEL 7 系统中设置SYSTEMD SERVICE的ULIMIT资源限制

    在bash中,有个ulimit命令,提供了对shell及该shell启动的进程的可用资源控制.主要包括打开文件描述符数量.用户的最大进程数量.coredump文件的大小等. 在centos 5/6 等 ...

  7. php如何解决中文乱码问题?

    为什么会出现中文乱码? 很多新手朋友学习PHP的时候,发现程序中的中文在输出的时候会出现乱码的问题,那么为什么会出现这种乱码的情况呢?一般来说,乱码的出现有2种原因,一种是由于编码(charset) ...

  8. 用pip下载的python模块怎么在PyCharm中引入报错

    在IDE中导入下载的模块,比如:numpy模块 你会发现虽然你安装了numpy模块,在CMD中python可以import numpy,但是你在PyCharm引不进去,为什么呢?你要是有注意的话,安装 ...

  9. https://oi-wiki.org/

    OI网站 https://oi-wiki.org/

  10. python学习日记(内置函数补充)

    剩余匿名函数 序列 序列——列表和元组相关的:list和tuple 序列——字符串相关的:str,format,bytes,bytearry,memoryview,ord,chr,ascii,repr ...