三沣开发知识 购物 网址 游戏 小说 歌词 地图 快照 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 开发 租车 短信 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题
autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml
html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> C# -> 重构手法之简化函数调用【6】 -> 正文阅读
 

[C#]重构手法之简化函数调用【6】

重构手法之简化函数调用【6】 返回总目录
本小节目录
Replace Error Code with Exception(以异常取代错误码) Replace Exception with Test(以测试取代异常) 13Replace Error Code with Exception(以异常取代错误码) 概要
某个函数返回一个特定的代码,用以表示某种特定的情况。改用异常。
动机
异常能清楚地将“普通程序”和“错误处理”分开了,这使得程序更容易理解。
代码的可理解性应该是我们虔诚追求的目标。
范例

class Account
{
    /// <summary>
    /// 余额
    /// </summary>
    private int _balance;
    /// <summary>
    /// 取款
    /// </summary>
    /// <param name="amount">取款金额</param>
    /// <returns></returns>
    public int Withdraw(int amount)
    {
        if (amount > _balance)
        {
            return -1;
        }
        _balance -= amount;
        return 0;
    }
    public bool CanWithdraw(int amount)
    {
        return amount <= _balance;
    }

    public void HandOverdran()
    {

    }

    public void DoTheUsualThing()
    {

    }
}

为了让这段代码使用异常,首先决定使用受控异常还是非受控异常。关键在于:调用者是否有责任在取款之前检查存款余额,还是应该由Withdraw()函数负责检查。如果“检查余额”是调用者的责任,那么“取款金额大于存款金额”就是一个编程错误,应该使用非受控异常。如果“检查余额”是Withdraw()函数的责任,就必须在函数中抛出这个异常。
范例:非受控异常
使用非受控异常就表示应该由调用者负责检查。首先需要检查调用端的代码,它不应该使用Withdraw()函数的返回值,因为返回值只是用来指出程序员的错误。如果看到这样的代码:

Account account = new Account();
if (account.Withdraw(100) == -1)
{
    account.HandOverdran();
}
else
{
    account.DoTheUsualThing();
}

应该将它替换成这样的代码:

Account account = new Account();
if (!account.CanWithdraw(100))
{
    account.HandOverdran();
}
else
{
    account.Withdraw(100);
    account.DoTheUsualThing();
}

现在移除错误码,并在程序出错时抛出异常。由于这种行为是异常的、罕见的,所以使用卫语句检查这种情况:

public void Withdraw(int amount)
{
    if (amount > _balance)
    {
        throw new ArgumentException("Amount too large.");
    }
    _balance -= amount;
}

范例:使用受控异常
受控异常的处理方式略有不同。首先可以新建一个合适的异常:

class  BalanceException:Exception
{
    
}

当然了,这里不新建也是可以的。
然后调整调用端如下:

Account account = new Account();    
try
{
    account.Withdraw(100);
    account.DoTheUsualThing();
}
catch (BalanceException ex)
{
    account.HandOverdran();
}

接下来修改Withdraw()函数,让它以异常表示错误状况:

public void Withdraw(int amount)
{
    if (amount > _balance)
    {
        throw new BalanceException();
    }
    _balance -= amount;
}

小结
将错误码替换成异常之后,使得代码更容易理解。

15Replace Exception with Test(以测试取代异常)  概要
面对一个调用者可以预先检查的条件,你抛出了一个异常。
修改调用者,使它在调用函数之前先做检查。
动机
异常可以协助我们避免很多复杂的错误处理逻辑。但是,异常也会被滥用。“异常”只应该被用于异常的、罕见的行为,也就是那些产生意料之外的错误的行为,而不应该成为条件检查的替代者。
范例
下面的例子中,以一个ResourcePool对象管理一些创建代价高昂而又可以重复使用的资源。这个对象带有两个“池”:一个用以保存可用资源,一个用以保存已分配资源。当用户请求一份资源时,ResourcePool对象从“可用资源池”中取出一份资源交出,并将这份资源转移到“已分配资源池”。当用户释放一份资源时,ResourcePool对象就该将资源从“已分配资源池”放回“可用资源池”。如果“可用资源池”不能满足用户的请求,ResourcePool对象就创建一份新资源。

class ResourcePool
{
    private Stack<Resource> _available;

    private Stack<Resource> _allocated;

    public Resource GetResource()
    {
        Resource result;
        try
        {
            result = _available.Pop();
            _allocated.Push(result);
            return result;
        }
        catch (Exception ex)
        {
            result = new Resource();
            _allocated.Push(result);
            return result;
        }
    }
}

class Resource
{

}

在这里,“可用资源用尽”并不是一件意料外的事件,因此不该使用异常表示这种情况。
为了去掉这里的异常,首先添加一个适当的提前测试,并在其中处理“可用资源为空”的情况:

class ResourcePool
{
    private Stack<Resource> _available;

    private Stack<Resource> _allocated;

    public Resource GetResource()
    {
        Resource result;
        if (_available.Count == 0)
        {
            result = new Resource();
            _allocated.Push(result);
            return result;
        }
        result = _available.Pop();
        _allocated.Push(result);
        return result;
    }
}

class Resource
{

}

在这里,可以对条件代码加以整理,使用Consolidate Duplicate Conditional Fragments:

class ResourcePool
{
    private Stack<Resource> _available;

    private Stack<Resource> _allocated;

    public Resource GetResource()
    {
        Resource result;
        if (_available.Count == 0)
        {
            result = new Resource();
        }
        else
        {
            result = _available.Pop();
        }     
        _allocated.Push(result);
        return result;
    }
}

class Resource
{

}

小结

 阶段性小结
在对象技术中,最红要的概念莫过于“接口”。容易被理解和被使用的接口,是开发良好面向对象软件的关键。
最简单也最重要的一件事就是修改函数名称。名称是程序写作者与阅读者交流的关键工具。只要能理解一段程序的功能,就应该大胆地使用Rename Method将所知道的东西传达给他人。
函数参数在接口中扮演十分重要的角色。Add Parameter和Remove Parameter都是很常见的重构手法。刚接触面向对象技术的程序员往往使用很长的参数列。但是,使用对象技术,可以保持参数列的简短。如果来自同一个对象的多个值被当做参数传递,可以运用Preserve Whole Object将它们替换为单一对象,从而缩减参数列。如果此前并不存在这样一个对象,可以运用Introduce Parameter Object将它创建出来。如果函数参数来自该函数可获取的一个对象,则可以使用Replace Parameter with Methods避免传递参数。如果某些参数被用来在条件表达式中做选择依据,可以实施Replace Parameter with Explicit Method。另外,还可以使用Parameterize Method为数个相似函数添加参数,将它们合并到一起。
明确地将“修改对象状态”的函数和“查询对象状态”的函数分开设计是一个很好的习惯。如果看到这两种函数混在一起,可以使用Separate Query from Modifier将它们分开。
良好的接口只向用户展现必须展现的东西。如果一个接口暴露了过多细节,可以将不必要暴露的东西隐藏起来,从而改进接口的质量。进行重构时,往往需要暂时暴露某些东西,最后再以Hide Method和Remove Setting Method将它们隐藏起来。
构造函数往往比较“麻烦”,因为它强迫你必须知道要创建的对象属于哪个类,而你往往并不需要知道这一点。可以使用Replace Constructor with Factory Method避免了这不必要的信息。
和许多现代编程语言一样,C#也有异常处理机制,这使得错误处理相对容易一些。不习惯使用异常的程序员,往往会以错误码表示程序遇到麻烦。可以使用Replace Error Code with Exception来运用新的异常特性。但有时候异常也并不是最合适的选择,应该实施Replace Exception with Test先测试一番。
To Be Continued……
  C# 最新文章
字符串阵列分别输出元素的索引,原值和长度
格式化你的字符串
C#宣告一个变量
C#中级
拆分一个字符串并把每个字符单独输出
通过手机号定位归属地
C#堆与栈
《C#微信开发系列(4)
线程基本概念
基于吉日嘎底层架构的Web端权限管理操作演示
上一篇文章      下一篇文章      查看所有文章
加:2017-12-05 23:21:41  更:2017-12-05 23:21:54 
 
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2017年12日历
2017-12-17 17:41:41
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库