热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《.NET设计规范》第9章:常用的设计模式

第9章:常用的设计模式9.1聚合组件考虑为常用的特性域提供聚合组件。要用聚合组件来对高层的概念(物理对象)进行建模,而不是对系统级的任务进行建模。要让聚合组件的名字与众所周知的系统

第 9 章:常用的设计模式

9.1 聚合组件

  考虑为常用的特性域提供聚合组件。

  要用聚合组件来对高层的概念(物理对象)进行建模,而不是对系统级的任务进行建模。

  要让聚合组件的名字与众所周知的系统实体相对应,比如 MessageQueue、Process 或 EventLog,这样就能使类型更加引人注目。

  要在设计聚合组件时使初始化尽可能地简单,这样用户只需进行简单的初始化就可以使用组件。如果某一项初始化是必需的,那么由于没有对组件进行初始化而引发的异常应该明确地告诉用户应该怎么做。

  不要要求聚合组件的用户在一个场景中显式地实例化多个对象。

  要保证让聚合组件支持 Create-Set-Call 使用模式,这样用户就可以先实例化组件,然后设置它的属性,最后调用一些简单的方法,以实现大多数场景。

  要为所有的聚合组件提供默认构造函数或非常简单的构造函数。

  要为聚合组件提供可读写的属性来与构造函数中的所有参数相对应。

  要在聚合组件中使用事件,不要使用基于委托的 API。

  考虑用事件来代替需要被覆盖的虚成员。

  不要要求聚合组件的用户在常用场景中使用继承、覆盖方法及实现接口。

  不要要求聚合组件的用户在常用场景中除了编写代码之外,还要做其他的做工。例如,不应该让用户用配置文件来配置组件,也不应该让用户生成资源文件,等等。

  考虑让聚合组件能够自动切换状态。

  不要涉及有多种状态的因子类型。

  考虑将聚合组件集成到 VS 的设计器中。

  考虑把聚合组件和因子类型分开,各自放在不同的程序集中。

  考虑把聚合组件内部的因子类型暴露给外界访问。

9.2 Async 模式

  要实现基于事件的 Async 模式 - 如果类型是一个支持可视化设计器的组件(也就是说类型实现了 IComponent)。

  要实现经典的 Async 模式 - 如果必须支持等待句柄。

  考虑在实现高层 API 时使用基于事件的 Async 模式。例如,聚合组件就应该实现该模式。

  考虑在实现底层 API 时使用经典的 Async 模式,在这种情况下更强大的功能、更少的内存消耗、更好的灵活性、更少的磁盘占用要比可用性更重要。

  避免在同一个类型中甚至是一组相关的类型中同时实现两种 Async 模式。

  要在为异步操作定义 API 时遵循下面的约定。给定名为 Operation 的同步方法,应该提供名为 BeginOperation 和 EndOperation 的方法,它们的方法签名如下面所示(注意,输出参数不是必需的)。

  要确保 Begin 方法的返回类型实现了 IAsyncResult 接口。

  要确保同步方法的按值传递和按引用传递的参数在 Begin 方法中都是按值传递的。同步方法的输出参数不应该出现在 Begin 方法的签名中。

  要确保 End 方法的返回类型与同步方法的返回类型相同。

  要确保同步方法的任何输出参数和按引用传递的参数都作为 End 方法的输出参数。同步方法中安置传递的参数不应该出现在 End 方法的签名中。

  不要继续执行异步操作 - 如果 Begin 方法抛出了异常。

  要一次通过下面的机制来通知调用方异步操作已经完成。

    将 IAsyncResult.IsCompleted 设为 true。

    激活 IAsyncResult.AsyncWaitHandle 返回的等待句柄。

    调用异步回调函数。

  要通过从 End 方法中抛出异常来表示无法成功地完成异步操作。

  要在 End 方法被调用时同步完成所有尚未完成的操作。。

  考虑抛出 InvalidOperationException 异常 - 如果用户用同一个 IAsyncResult 两次调用 End 方法,或 IAsyncResult 是从另一个不相关的 Begin 方法返回的。

  要把 IAsyncResult.CompletedSynchronously 设为 true - 当且仅当异步回调函数将在调用 Begin 方法的线程中运行的时候。

  要确保在正确的线程中调用事件处理程序。与经典 Async 模式相比,这是使用基于事件的 Async 模式的主要好处之一。

  要确保无论是操作已经完成,还是操作出错,还是操作被取消,都是种会调用事件处理程序。不应该让应用程序无休止地等待一间永远不会发生的事件

  要确保在异步操作失败后,访问时间参数类的属性会引发异常。换句话说,如果有错误导致操作无法完成,那么就不应该允许用户访问操作的结果。

  不要为返回值为空的方法定义新的事件处理程序或事件参数类型。要使用 AsyncCompletedEventArgs,AsyncCompletedEventHandler 或 EventHandler。

  要确保如果在一个一步操作中实现了 PaogressChanged 事件,那么在操作的完成事件被触发之后,不应该再出现此类事件。

  要确保如果使用了标准的 ProgressChangedEventArgs,那么 ProgressPercentage 始终能用来表示进度的百分比(不一定要完全精确,但表示的一定要百分比)。如果使用的不是标准进度,那么从 ProgressChangedEventArgs 派生一个子类会更合适,这种情况下应该保持 ProgressPercentage 为 0 ;

  要在有增量结果需要报告的时候出发 ProgressChanged 事件。

  要对 ProgressChangedEventArgs 进行扩展来保存增量结果数据,并用扩展后的时间参数类来定义 ProgressChanged 事件。

  要把增量结果报告与进度报告分开。

  要为每个异步操作定义单独的 ProgreessChanged 事件和相应的事件参数类,来处理该操作的增量结果数据。

9.3 依赖属性

  要提供依赖属性 - 如果需要用他们来支持各种 WPF 特性,比如样式、触发器、数据绑定、动画、动态资源以及继承。

  要在设计依赖属性的时候继承自 DependencyObject 或它的子类型。该类型实现的属性存储区非常高效,它还自动支持 WPF 的数据绑定。

  要为每个依赖属性提供常规的 CLR 属性和存放 System.Windows.DependencyProperty 实例的公有静态只读字段。

  要通过调用 DependencyObject.GetValue 和 DependencyObject.SetValue 的方式来实现依赖属性。

  要用依赖属性的名字加上“Property”后缀来命名依赖属性的静态字段。

  不要显式地在代码中设置依赖属性的默认值,应该在元数据中设置默认值。

  不要在属性的访问器中添加额外的代码,而应该使用标准代码来访问静态字段。

  不要使用依赖属性来保存保密数据。任何代码都能访问依赖属性,即使它们是私有的。

  不要把依赖属性的验证逻辑放在访问器中,而应该把验证毁掉函数传给 DependencyProperty.Register 方法。

  不要在依赖属性的访问器中实现属性改变的通知,而应该向 PropertyMetadata 注册改变通知的回调函数,后者是依赖属性本身提供的一项特性,为了支持改变通知,必须使用该特性。

  不要在依赖属性的访问器中实现属性强制赋值逻辑,而应该向 PropertyMetadata 注册强制赋值的回调函数。后者是依赖属性本身提供的一项特性,为了支持强制赋值,必须使用该特性。

9.4 Disopse 模式

  要为含有可处置类型实例的类型实现基本 Dispose 模式。

  要为类型实现基本 Dispose 模式并提供终结方法 - 如果类型持有需求由开发人员显式释放的类型,而且后者本身没有终结方法。

  考虑为类实现基本 Dispose 模式 - 如果类本身并不持有非托管资源或可处置对象,但是它的子类型却可能会持有非托管资源或可处置对象。

  要按下面的方法来实现 IDisposable 接口,即先调用 Dispose(true),然后再调用 GC.SuppressFinalize(this)。

  不要将无参数的 Dispose 方法定义为虚方法。

  不要为 Dispose 方法声明除了 Dispose() 和 Dispose(bool) 之外的任何其它重载方法。

  要允许多次调用 Dispose(bool) 方法。他可以在第一次调用之后就什么也不做。

  避免从 Dispose(bool) 方法中抛出异常,除非是紧急情况,所处的进程已经遭到破坏(比如泄漏、共享状态不一致,等等)。

  要从成员中抛出 ObjectDisposedException 异常 - 如果该成员在对象终结之后就无法继续使用。

  考虑在 Dispose() 方法之外在提供一个 Close() 方法 - 如果 close 是该领域中的一个标准术语。

  避免定义可终结类型。

  不要定义可终结的值类型。

  要将类型定义为可终结类型 - 如果该类型要负责释放非托管资源,且非托管资源本身不具备终结方法。

  要为所有的可终结类型实现基本 Dispose 模式。

  不要在终结方法中访问任何可终结对象,这样做存在很大的风险,因为被访问的对象可能已经被终结了。

  要将 Finalize 方法定义为受保护的。

  不要在终结方法中放过任何异常,除非是致命的系统错误。

  考虑创建一个用于紧急情况的可终结对象 - 如果终结方法在应用程序域被强制卸载或线程异常退出的情况下都务必要执行。

9.5 Factory 模式

  要优先使用构造函数,而不是优先使用工厂,因为与特殊的对象构造机制相比,构造函数一般来说更容易使用、更一致,也更方便。

  考虑使用工厂 - 如果构造函数提供的对象创建机制不能满足要求。

  要使用工厂 - 如果开发人员可能不清楚待创建的对象的确切类型,比如对基类或接口编程就属于这种情况。

  考虑使用工厂方法 - 如果这是让操作不言自明的唯一方法。

  要在转换风格的操作中使用 factory。

  要尽量将工厂操作方法实现为方法,而不是实现为属性。

  要通过方法的返回值而不是方法的输出参数来返回新创建的对象实例。

  考虑把 Create 和要创建的类型名连在一起,一次来命名工厂方法。

  考虑把要创建的类型名和 Factory 连在一起,一次来命名工厂类型。例如,可以考虑把创建 Control 对象的工厂类型命名为 ControlFactory。

9.6 对 LINQ 的支持

  要实现 IEnumerabl,其目的是为了得到基本的 LINQ 支持。

  考虑实现 ICollection,其目的是为了提高查询的性能。

  考虑实现 IQueryable - 如果必须要访问传给 IQueryable 的成员的查询表达式。

  不要草率地实现 IQueryable,要理解这样做可能会对性能产生什么影响。

  要在 IQueryable 的方法中抛出 NotSupportedException - 如果你的数据源上不支持该操作。

  要在新类型中将 Query 模式实现为实例方法 - 如果在 LINQ 以外的场合,这些方法在类型中仍然有存在的意义。否则,应该将它们实现为扩展方法。

  要让实现了 Query 模式在类型实现了 IEnumerable

  考虑在设计 LINQ 操作符时,让它们返回领域特有的可枚举类型。虽然从本质上来说,Select 查询方法可以返回任何类型,但是大家通常都希望查询的结果是可枚举类型。

  避免只实现 Query 模式的一部分 - 如果不希望退回到基本的 IEnuerable 实现。

  要为有序序列定义单独的类型,从而将它和对应的无序序列分开。这样的类型应该定义 ThenBy 方法。

  要推迟执行实际的查询操作。对 Query 模式的大多数成员来说,我希望它们只是创建一个新的对象,并在枚举的时候才产生集合重负荷查询条件的元素。

  要将用于查询的扩展方法放在主命名空间中的一个名为“Linq” 的子命名空间中。例如,为 System.Data 特性定义的扩展方法被放在 System.Data.Linq 命名空间。

  要在参数中使用 Expression>,而不是 Func<...> - 如果需要查询查询表达式。

9.7 Optional Feature 模式

  考虑将 Optional Feature 模式用于抽象中的可选特性。

  要提供一个简单的布尔属性来让用户检测对象是否支持可选特性。

  要在积累中将可选特性定义为虚方法,并在该方法中抛出 NotSupportedException 异常。

9.8 Simulated Convariance 模式

  考虑使用 Simulated Convariance 模式 - 如果需要有一种统一的类型来表示泛型类型的所有实例。

  要确保以等价的方式来实现根基类型成员和对应的泛型类型成员。

  考虑使用抽象基类来表示根基类型,而不是使用接口来表示根基类型。

  考虑用非泛型类型作为根基类型 - 如果这样的类型已经存在。

9.9 Template Method 模式

  避免将公有成员定义为虚成员。

  考虑使用 Template Method 模式来更好地控制扩展性。

  考虑以非秀成员的名字加“Core”后缀为名字,来命名为该费虚成员提供扩展点的受保护的虚成员。

9.10 超时

  要优先让用户通过参数来制定超时长度。

  要优先使用 TimeSpan 来表示超时长度。

  要在超时后抛出 System.TimeoutException 异常。

  不要通过返回错误码的方式来告诉用户发生了超时。

9.11 可供 XAML 使用的类型

  考虑提供默认构造函数 - 如果想让类型能用于 XAML。

  要提供标记扩展 - 如果想让 XAML 读取程序能够创建不可变的类型。。

  避免定义新的类型转换器,除非这样的转换是自然而直观的。一般来说,应该将类型转换器的使用范围限制在 .NET 框架中已经使用了类型转换器的地方。

  考虑将 ContentPropertyAttribute 用于最常用的属性,从而得到更方便的 XAML 语法。

《.NET 设计规范》第 9 章:常用的设计模式


推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
author-avatar
love留着对她说吧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有