`
ribishuangba
  • 浏览: 292734 次
文章分类
社区版块
存档分类
最新评论

On Extension Method: 扩展方法该如何使用

 
阅读更多

Herb Sutter 曾经有一个观点, 就是一个组件的接口, 不只包括这个组件本身定义的方法, 还包括使用这个组件的客户代码, 比如以这个组件为参数的那些方法. 扩展方法是对Herb Sutter这个观点所做的语法上的支持: 把以这个组件为参数的那些客户代码转变成扩展方法后, 调用时从语法上看起来跟调用这个组件本身定义的方法一模一样了!

---------------------现实的分割线------------------------

上面只是一厢情愿的历史溯源. 真实的情况是扩展方法是为了 LINQ 而加进来的, 就为了是表达式看起来干净漂亮些: videoList.Where(video => video.Rate > 18).Select(video => video.Title);

然而这种语法上的便利和优雅, 鼓励了一种原本在面向对象设计中就争论颇多的设计元素的更加随意的使用: 静态方法. 扩展方法只不过是抹了糖的静态方法.

我们需要整理一下扩展方法的应用场景.

考察一下LINQ. LINQ 为 IEnumerable 添加的扩展方法有几个特点:

  • 是业务无关的通用算法. 无论你是开发桌面应用还是web app, 无论是金融电信等行业软件, 还是博客聊天等个人工具, 都可以从这些通用的扩展方法中受益.

  • 是全局的, public的. 这应该是上一个特点带来的不得不这样的一种选择.

  • 目的是表达式的可读性

LINQ是对扩展方法的一种成功应用, 也是我所知的唯一一种大范围使用的应用. 鉴于扩展方法也原本是为LINQ而引入的, 所以你可以认为LINQ所代表的应用场景就是扩展方法应该的应用场景. 项目中较为成功的扩展方法应用是为 object 扩展了 ShouldBe 方法用于测试中, 比如:

public static void ShouldBe(this object actual, object expected)

{

Assert.Equals(actual, expected);

}

用起来是 actual.ShouldBe(expected); 完全满足上面的三个特性.

再考察一下工作中曾经遇到的有争论的扩展方法的应用场景

最争议的是业务相关的逻辑应该不应该用扩展方法来表达, 业务模型应该不应该用扩展方法来扩展? General的回答是不应该. 毕竟是静态方法, 意味着某种业务概念的缺失, 应该有更好的封装方法. 但不妨以扩展方法开始: 曾经发生过的例子是我们最开始为HttpRequest创建了一个我们的业务相关的扩展方法, 而在接下来的几周内我们不断的为HttpRequest添加业务相关的扩展方法, 最终我们发现这几个方法合在一起其实是我们的一个领域概念.

在从扩展方法过渡到领域模型的过程中, 有一些跟上面几条不一样的规则:

  • 扩展方法应该是internal的, 因为是业务相关的, 必然只在当前Context下有效, 我们不希望在其它Context下它们也被IDE的智能提示带出来

  • 扩展方法所在的类不应该以所扩展的类或接口来命名, 比如不应该叫 HttpRequestExtensions, StringExtensions, 而应该以业务概念来命名. 这样更meaningful, 以后的过渡也会比较自然

  • 扩展方法应该放在靠近使用它的地方, 而不是放在它所扩展的类或接口旁边. 这是第一条规则的推论, 也是Herb Sutter理论的推论, 因为这种场景下的扩展方法的实现代码其实原本是客户代码, 本来就应该放在使用它的地方.

从这个角度来说, 扩展方法的出现是一个信号, 意味着所扩展对象的一个新的Context出现了. 因此扩展方法和 DCI 可以看作是对同一个问题的两种不同解答, 两者某种程度上都是为了解决可读性.

最后说个题外话, 扩展方法比一般实例方法有一个好处, 就是可以对象实例为null时可以不必抛出NullReferenceException, 因为此时对象实例是作为参数传进来, 可以做判断给出更有意义的异常.

分享到:
评论

相关推荐

    重构_改善既有代码的设计[高清版]中文版

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    重构-改善既有代码的设计+中文版

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    重构——改善既有代码的设计

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    重构-改善既有代码的设计(中文版)

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    重构,改善既有代码的设计

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    重构 改善既有代码的设计

     *Introduce Local Extension 引入本地扩展类  Chapter 8:Organizing Data 组织数据   Self Encapsulate Field 自封装字段   Replace Data Value with Object 用对象代替数据值   Change Value to ...

    [傻瓜编程系列].LINQ.for.Dummies

    * Examine .NET language extensions and work with extension methods, partial methods, lambda expressions, and query expressions * LINQ to DataSet operators, SQL server operations, XML API, or Active ...

    ZendFramework中文文档

    14.1.3. 使用静态 get() 方法 14.2. 标准过滤器类 14.2.1. Alnum 14.2.2. Alpha 14.2.3. BaseName 14.2.4. Digits 14.2.5. Dir 14.2.6. HtmlEntities 14.2.7. Int 14.2.8. RealPath 14.2.9. StringToLower...

    Spring中文帮助文档

    3.3.3. 使用depends-on 3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton ...

    Spring API

    3.3.3. 使用depends-on 3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton ...

    Visual C++ 编程资源大全(英文源码 其它)

    1,01.zip Output 显示所有的调试信息(5KB)<END><br>2,02.zip Some general debugging tips 一般的调试技巧(11KB)<END><br>3,03.zip Debugging ISAPI extension 调试ISAPI扩展(4KB)<END><br>4,04....

    Visual C++ 编程资源大全(英文源码 表单)

    1,01.zip MFC Extension Library MFC扩展界面库, 使用Visual C++ 6.0(15KB)<END><br>2,02.zip Visual Studio style UI Visual Studio风格的界面效果(15KB)<END><br>3,03.zip Internet Explorer 4 ...

Global site tag (gtag.js) - Google Analytics