8.2 OOP技术
下面讨论对象的其他一些特性,包括:
接口
继承
多态性
对象之间的关系
运算符重载
事件
引用类型和值类型
8.2.1 接口
接口是把公共实例(非静态)方法和属性组合起来,以封装特定功能的一个集合。
一且定义了接口,就可以在类中实现它。这样,类就可以支持接口所指定的所有属性和成员。
注意,接口不能单独存在。不能像实例化一个类那样实例化接口。另外,接口不能包含实现其成员的任何代码,而只能定义成员本身。实现过程必须在实现接口的类中完成。
在前面的咖啡示例中,可以把通用属性和方法例如 AddSugar()、Milk、Sugar 和 Instant 组合到一个接口中,这个接口称为IHotDrink(接口的名称一般用大写字母I开头)。然后就可以在其他对象上使用该接口,例如 CupOfTea 类的对象。所以可以用类似的方式处理这些对象,而对象仍保有自己的属性(例如CupOfCoffee仍有属性BeanType,CupOfTea仍有属性LeafType)。
在UML中,在对象上实现的接口用“棒棒糖”语法来表示。在图8-6 中,用与类相似的语法把IHotDrink的成员放在一个单独的框中。
一个类可以支持多个接口,多个类也可以支持相同的接口。所以接口的概念让用户和其他开发人员更容易理解其他人的代码。
例如,有一些代码使用一个带某接口的对象。假定不使用这个对象的其他属性和方法,就可以用另一个对象代替这个对象(例如,使用上述IHotDrink接口的代码可以处理CupOfCoffee和CupOfTea实例)。另外,该对象的开发人员可以提供该对象的更新版本,只要
它支持已经在用的接口,就可以在代码中使用这个新版本。
在发布接口后,即接口可以用于其他开发人员或终端用户后,最好不要修改它。理解这一点的一种方式是把接口看作类的创建者和使用者之间的契约。“每个支持接口 X 的类都支持这些方法和属性”是有效的。如果以后修改了接口,也许是升级了底层的代码,该接口的使用者就不能正确运行接口,甚至失败。我们应创建一个新的接口,来扩展旧接口,例如包含一个版本号,如X2。这是创建接口的标准方式,以后我们会常常遇到编了号的接口。
可删除的对象
IDisposable接口特别有趣。支持IDisposable接口的对象必须实现其Dispose()方法,即它们必须提供这个方法的代码。当不再需要某个对象(例如,在对象超出作用域之前)时,就调用这个方法,释放重要的资源,否则,该资源会等到对垃圾回收调用析构方法时才释放。这样可以更好地控制对象所使用的资源。
C#允许使用一种可以优化使用这个方法的结构。using 关键字可以在代码块中初始化使用重要资源的对象,会在这个代码块的末尾自动调用Dispose()方法,用法如下:
<ClassName> <VariableName> = new <ClassName>(); ... using (<VariableName>) { ... }
或者把初始化时象<VariableName>作为using语句的一部分:
using (<ClassName> <VariableName> = new <ClassName>()) { ... }
在这两种情况下,可以在using代码块中使用变量<VariableName>, 并在代码块的末尾自动删除(在代码块执行完毕后,调用Dispose())