类库开发的设计准则 读书笔记 2类型设计准则

MSDN链接:http://msdn.microsoft.com/zh-cn/library/vstudio/ms229036(v=vs.100).aspx

  系列文章列表:

  1名称准则:http://www.cnblogs.com/liu-meng/p/4181984.html

  2类型设计准则:http://www.cnblogs.com/liu-meng/p/4182737.html

类型与命名空间:

  使用命名空间将类型组织到相关功能区域的的层次结构中

  避免使用较深的命名空间层次结构

  避免使用过多的命名空间

  避免将设计用于高级方案的类型与设计用于常见编程任务的类型放到同一命名空间中,一般情况下,应将高级类型放入一般命名空间内的某个命名空间中,并将 Advanced 用作该命名空间的名称的最后一个标识符,例如,与 XML 序列化相关的常用类型位于System.Xml.Serialization 命名空间中,而高级类型则位于 System.Xml.Serialization.Advanced 命名空间中。

  定义类型时要指定类型的命名空间。

在类和结构之间选择:

  类是引用类型,而结构是值类型。 引用类型在堆中分配,内存管理由垃圾回收器处理。 值类型在堆栈上或以内联方式分配,且在超出范围时释放。 通常,值类型的分配和释放开销更小。 然而,如果在要求大量的装箱和取消装箱操作的情况下使用,则值类型的表现就不如引用类型。

  如果类型的实例不大,且通常生存期短或嵌入其他对象,则考虑定义结构而不是类。

  不要定义结构,除非该类型具备以下所有特征:

    •   它在逻辑上表示单个值,与基元类型(整型、双精度型等)类似。
    •   它的实例大小小于 16 字节。
    •   它是不可变的。
    •   它将不必频繁被装箱。

在类和接口之间选择:

  接口定义实施者必须提供的一组成员的签名。 接口不能提供成员的实现细节。 实现该接口的每个类都必须提供这些成员的实现细节。 类可以实现多个接口。

  类定义每个成员的成员签名和实现细节。 Abstract (在 Visual Basic 中为 MustInherit)类的行为在某方面与接口或普通类相同,即可以定义成员,可以提供实现细节,但并不要求一定这样做。 如果抽象类不提供实现细节,从该抽象类继承的具体类就需要提供实现。

  虽然抽象类和接口都支持将协定与实现分离开来,但接口不能指定以后版本中的新成员,而抽象类可以根据需要添加成员以支持更多功能。

  优先考虑定义类,而不是接口。在库的以后版本中,可以安全地向类添加新成员;而对于接口,则只有修改现有代码才能添加成员。

  请使用抽象(在 Visual Basic 中为 MustInherit)类,而不要使用接口来分离协定与实现。如果需要提供多态层次结构的值类型,则应定义接口。值类型必须从 ValueType 继承,并且只能从 ValueType 继承,因此值类型不能使用类来分离协定和实现。 这种情况下,如果值类型要求多态行为,则必须使用接口。

  请考虑定义接口来达到类似于多重继承的效果。如果一个类型必须实现多个协定,或者协定适用于多种类型,请使用接口。

抽象类设计:

  不要在抽象类型中定义公共的或受保护的内部(在 Visual Basic 中为 Protected Friend)构造函数

  应在抽象类中定义一个受保护构造函数或内部构造函数。如果在抽象类中定义一个受保护构造函数,则在创建派生类的实例时,基类可执行初始化任务。 内部构造函数可防止抽象类被用作其他程序集中的类型的基类。

  对于您提供的每个抽象类,至少应提供一个具体的继承类型。

静态类的设计:

  静态类只包含从 Object 继承的实例成员,也没有可调用的构造函数。

  请慎用静态类。静态类只应用作面向对象的框架核心的支持类。

  不要认为静态类可无所不包。Environment 类使用静态类的方式值得学习。 此类提供对当前用户环境的信息的访问。

  不要声明或重写静态类中的实例成员。如果某个类设计了实例成员,则该类不应标记为静态的。

  如果编程语言没有对静态类的内置支持,则应将静态类声明为密封的和抽象的,并添加一个私有实例构造函数。

接口的设计:

  接口定义实施者必须提供的一组成员的签名。 接口不能提供成员的实现细节。 实现该接口的每个具体类都必须提供这些成员的实现细节。虽然类只能从单个类继承,但可以实现多个接口。

  如果一组包含某些值类型的类型需要支持某些常用功能,则必须定义接口。

  如果从某些其他类型继承的类型需要支持其功能,则考虑定义接口。

  避免使用标记接口(没有成员的接口)。自定义特性提供了一种标记类型的方式。如果可以将特性检查推迟到执行代码时才进行,则首选自定义特性。 如果需要进行编译时检查,则不能使用此准则。

  请提供至少一种接口实现的类型。

  对于定义的每个接口,请提供至少一个使用该接口的成员(例如,采用该接口作为参数的方法,或类型化为接口的属性)。这是另一种有助于确保正确设计和顺利使用接口的机制。

  不要向以前提供的接口添加成员。

结构的设计:

  结构是值类型。 结构是在堆栈上或以内联方式分配的,当结构超出范围时将被释放。 通常情况下,值类型的内存空间分配和释放的开销较小;但在需要大量装箱和取消装箱操作的方案中,值类型的执行性能较引用类型要差。 有关更多信息,请参见装箱和取消装箱(C# 编程指南)

  不要为结构提供默认的构造函数。如果某一结构定义了默认构造函数,则在创建该结构的数组时,公共语言运行时会自动对每个数组元素执行该默认构造函数。有些编译器(如 C# 编译器)不允许结构拥有默认构造函数。

  对值类型实现 System.IEquatable`1。在确定两个值类型是否相等时,IEquatable<T> 要优于 Equals。 通过使用接口,调用方可避免装箱和托管反射的不良性能影响。

  不要显式扩展 System.ValueType。有些编译器不允许扩展 ValueType。

  确保所有实例数据均设置为零、false 或 null(根据需要)的状态是无效的。如果遵循这一准则,新构造的值类型实例不会处于不可用的状态。

例如,下面的结构的设计是错误的。 参数化构造函数有意确保存在有效的状态,但在创建结构数组时不执行该构造函数。 这意味着实例字段 label 初始化为 null(在 Visual Basic 中为 Nothing),这对于此结构的 ToString 实现是无效的。

  
public  struct BadStructure
{
    string label;
    int width;
    int length;

    public BadStructure (string labelValue, int widthValue, int lengthValue)
    {
        if (labelValue == null || labelValue.Length ==0)
        {
            throw new ArgumentNullException("label");
        }
        label = labelValue;
        width = widthValue;
        length = lengthValue;
    }

    public override string ToString()
    {
        // Accessing label.Length throws a NullReferenceException
        // when label is null.
        return String.Format("Label length: {0} Label: {1} Width: {2} Length: {3}",
            label.Length, label, width,length);
    }
}

在下面的代码示例中,GoodStructure 的设计对 label 字段的状态未作任何假定。 ToString 方法设计为处理 null 标签。  

public  struct GoodStructure
{
    string label;
    int width;
    int length;

    public GoodStructure (string labelValue, int widthValue, int lengthValue)
    {
        label = labelValue;
        width = widthValue;
        length = lengthValue;
    }

    public override string ToString()
    {
        // Handle the case where label might be
        // initialized to null;
        string formattedLabel = label;
        int formattedLableLength;
        if (formattedLabel == null)
        {
            formattedLabel = "<no label value specified>";
            formattedLableLength = 0;
        } else
        {
            formattedLableLength = label.Length;
        }
        return String.Format("Label Length: {0} Label: {1} Width: {2} Length: {3}",
            formattedLableLength, formattedLabel, width, length);
    }
}

枚举的设计:

  枚举提供成组的常数值,它们有助于使成员成为强类型以及提高代码的可读性。 枚举分为简单枚举和标志枚举两种。 简单枚举包含的值不用于组合,也不用于按位比较。 标志枚举应使用按位 OR 操作进行组合。 标志枚举值的组合使用按位 AND 操作检查。
  一定要使用枚举强类型化参数、属性和表示值集的返回值。

  一定要优选使用枚举而不是静态常量。

  不要对开放集(如操作系统版本)使用枚举。

  不要定义供将来使用的保留枚举值。某些情况下,您可能认为为了向提供的枚举添加值,值得冒可能中断现有代码的风险。 还可以定义使用其值的新的枚举和成员。

  避免公开只有一个值的枚举。

  一定不要将 sentinel 值包括在枚举中。Sentinel 值用于标识枚举中的值的边界。 通常,sentinel 值用于范围检查,它不是一个有效的数据值。 下面的代码示例定义一个带有 sentinel 值的枚举。

public enum Furniture
{
    Desk,
    Chair,
    Lamp,
    Rug,
    LastValue   // The sentinel value.
}

  

  一定要在简单枚举中提供一个零值。如果可能,将此值命名为 None。 如果 None 不适合,请将零值赋给最常用的值(默认值)。

  考虑将 System.Int32(大多数编程语言的默认数据类型)用作枚举的基础数据类型,除非出现以下任何一种情况:

    •   枚举是标志枚举,且您有 32 个以上的标志或者期望在将来有更多的标志。
    •   基础类型需要与 Int32 不同,以便易于与期望不同大小的枚举的非托管代码进行互操作。
    •   较小的基础类型可以节省大量空间。 如果期望枚举主要用作控制流的参数,其大小就不太重要。 如果出现下面的情况,大小节省可能会很重要:
      •   期望枚举被用作非常频繁地实例化的结构或类中的字段。
      •   期望用户创建枚举实例的大型数组或集合。
      •   预计要序列化大量枚举实例。

  一定要以名词或名词词组的复数来命名标志枚举。 简单枚举应以单数的名词或名词词组命名。

  不要直接扩展 System.Enum。

嵌套类型:

  嵌套类型是作为某其他类型的成员的类型。 嵌套类型应与其声明类型紧密关联,并且不得用作通用类型。 有些开发人员会将嵌套类型弄混淆,因此嵌套类型不应是公开可见的,除非不得不这样做。 在设计完善的库中,开发人员几乎不需要使用嵌套类型实例化对象或声明变量。

  在声明类型使用和创建嵌套类型实例时,嵌套类型很有用,但不在公共成员中公开嵌套类型的使用。

  如果嵌套类型和其外部类型之间的关系需要成员可访问性语义,则要使用嵌套类型。由于嵌套类型被视为是声明类型的成员,因此嵌套类型可以访问声明类型中的所有其他成员。

  不要将公共嵌套类型用作逻辑分组构造;请改用命名空间。

  避免公开显露嵌套类型。 唯一的特例是需要声明嵌套类型的变量的情况,在生成子类或其他高级自定义等极少数情况下需要声明嵌套类型的变量。

  如果可能在声明类型的外部引用类型,则不要使用嵌套类型。在常见方案中,不应要求对嵌套类型进行变量声明和对象实例化。 例如,处理在某一类上定义的事件的事件处理程序委托不应嵌套在该类中。

  如果需要由客户端代码实例化类型,则不要使用嵌套类型。 如果某种类型具有公共构造函数,就可能不应进行嵌套。

  不要将嵌套类型定义为接口的成员。 许多语言不支持这样的构造。

时间: 2024-08-10 15:09:23

类库开发的设计准则 读书笔记 2类型设计准则的相关文章

规模化微服务——《微服务设计》读书笔记

    系列文章目录:     <微服务设计>读书笔记大纲 改变思维的角度:故障无处不在 当微服务规模化后,故障是无可避免的,以往我们总是想尽力避免故障的发生,而当故障实际发生时,我们往往束手无策.我们花了很多时间在流程设计和应用设计的层面上来阻止故障的发生,但实际上很少花费时间思考如何第一时间从故障中恢复过来. 一些公司喜欢组织活动,活动当天系统会被关掉以模拟故障发生,然后不同团队演练如何应对这种情况.这些项目中最著名的是混乱猴子(Chaos Monkey),在一天的特定时间随机停掉服务器,

《Java web 开发实战经典》读书笔记

去年年末,也就是大四上学期快要结束的时候,当时保研的事情确定了下来,终于有了一些空闲的时间可以学点实用的技术. 之前做数据库课程设计的时候,也接触过java web的知识,当时做了一个卖二手书籍的网站,但是由于掌握的技术不够,最后做出来的东西勉强能应付答辩.所以,想抽出时间继续昨晚这个项目.当时,我有些找工作的同学,已经在北京经历了找工作的艰辛,所以他们时常会举办一些小讲座,给学弟学妹传授找工作的经验,我也从这上面学到不少东西.<Java web 开发实战经典>这本书便是以为找工作的同学浩哥给

【重构:改善既有代码的设计】读书笔记——开篇

[重构:改善既有代码的设计]读书笔记总目录 1.重构原则 2.代码的坏味道[1] 3.代码的坏味道[2] 4.代码的坏味道[3] 5.代码的坏味道[4] 6.重构手法之Extrct Method(提炼函数).Inline Method(内联函数).Inline Temp(内联临时变量) 7.重构手法之Replace Temp With Query(以查询取代临时变量) 边写边更新吧...... 背景介绍 重构,一言以蔽之,就是在不改变外部行为的前提下,有条不紊地改善代码. 重构不只可以改善既有的

《微服务设计》读书笔记大纲

cha1:微服务的概念--<微服务设计>读书笔记 cha2:微服务架构师的职责--<微服务设计读书笔记> cha3:建模:确定服务的边界--<微服务设计>读书笔记 cha4:微服务集成--<微服务设计>读书笔记 服务的协作:服务间的消息传递--<微服务设计>读书笔记 cha5:拆分:分解单块系统--<微服务设计>读书笔记 cha6:部署:持续集成(CI)与持续交付(CD)--<微服务设计>读书笔记 cha7:测试--<

《android开发艺术探索》读书笔记(五)--动画

接上篇<android开发艺术探索>读书笔记(五)--Drawable No1: 自定义动画:派生一种新动画只需要继承Animation这个抽象类,然后重写它的initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中进行相应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程. No2: 属性动画PropertyAnimation 补间动画TweenAnimation 帧动画Frame

《android开发艺术探索》读书笔记(十三)--综合技术

接上篇<android开发艺术探索>读书笔记(十二)--Bitmap的加载和Cache No1: 使用CrashHandler来获取应用的crash信息 No2: 在Android中单个dex文件所能够包含的最大方法数为65536,这包含Android FrameWork.依赖的jar包以及应用本身的代码中的所有方法. No3: 使用multidex来解决方法数越界 apply plugin: 'com.android.application' android { compileSdkVers

《android开发艺术探索》读书笔记(十五)--Android性能优化

接上篇<android开发艺术探索>读书笔记(十四)--JNI和NDK编程 No1: 如果<include>制定了这个id属性,同时被包含的布局文件的根元素也制定了id属性,那么以<include>指定的id属性为准 No2: 绘制优化 1)onDraw中不要创建新的局部对象 2)onDraw方法中不要做耗时的任务 No3: 内存泄露优化 场景一:静态变量导致的内存泄露: 如果静态变量持有了一个Activity,会导致Activity无法及时释放. 解决办法:1使用Ap

&lt;&lt;操作系统精髓与设计原理&gt;&gt;读书笔记(一) 并发性:互斥与同步(1)

<<操作系统精髓与设计原理>>读书笔记(一) 并发性:互斥与同步 并发问题是所有问题的基础,也是操作系统设计的基础.并发包括很多设计问题,其中有进程间通信,资源共享与竞争,多个进程活动的同步以及分配给进程的处理器时间的. 和并发相关的关键术语:原子操作: 一个或多个指令的序列,对外是不可分的:即没有其他进程可以看到其中间状态或者中断此操作. 并发中,为了确保并发下的数据完整性,我们有一系列的同步方法,其实这些就是为了实现互斥性!对临界区程序的互斥性.有三种方法: 1.软件方法,但是

类库开发的设计准则 读书笔记 1名称准则

MSDN链接:http://msdn.microsoft.com/zh-cn/library/vstudio/ms229042(v=vs.100).aspx 系列文章列表: 1名称准则:http://www.cnblogs.com/liu-meng/p/4181984.html 2类型设计准则:http://www.cnblogs.com/liu-meng/p/4182737.html 大小写的样式: Pascal 大小写 将标识符的首字母和后面连接的每个单词的首字母都大写. 可以对三字符或更多