抽象类在类的继承中提供了一个常规的“祖先”。一个接口描述 了一个可以被其它类型实现的原子级泛型功能。各有千秋,却也不尽相同。接口 是一种合约式设计:一个类型实现了某个接口的类型,就必须实现某些期望的方 法。抽象类则是为一个相关类的集合提供常规的抽象方法。这些都是老套的东西 了:它是这样的,继承就是说它是某物(is a,),而接口就是说它有某个功能 (behaves like.)! 这些陈词滥调已经说了好久了,因为它们提供了说明,同时 在两个结构上描述它们的不同:基类是描述对象是什么,接口描述对象有某种行为。
接口描述了一组功能集合,或者是一个合约。你可以在接口里创建 任何的占位元素(placeholder,译注:就是指先定义,后面再实现的一些内容) :方法,属性,索引器以及事件。任何实现类型这个接口的类型必须为接口里的 每个元素提供具体的内容。你必须实现所有的方法,提供全部属性访问器,索引 器,以及定义接口里的所有事件。你在接口里标记并且构造了可重用的行为。你 可以把接口当成参数或者返回值,你也可以有更多的机会重用代码,因为不同的 类型可以实现相同的接口。更多的是,比起从你创建的基类派生,开发人员可以 更容易的实现接口。(译注:不见得!)
你不能在接口里提供任何成员的具 体实现,无论是什么,接口里面都不能实现。并且接口也不能包含任何具体的数 据成员。你是在定义一个合约,所有实现接口的类型都应该实现的合约。
抽象的基类可以为派生类提供一些具体的实现,另外也描述了一些公共 的行为。你可以更详细的说明数据成员,具体方法,实现虚函数,属性,事件以 及索引器。一个基类可以只提供部份方法的实现,从而只提供一些公共的可重用 的具体实现。抽象类的元素可以是虚的,抽象的,或者是非虚的。一个抽象类可 以为具体的行为提供一个可行的实现,而接口则不行。
重用这些实现还 有另一个好处:如果你在基类中添加一个方法,所有派生类会自动隐式的增加了 这个方法。这就是说,基类提供了一个有效的方法,可以随时扩展几个(派生)类 型的行为:就是向基类添加并实现方法,所有派生类会立即具有这些行为。而向 一个接口添加一个方法,所会破坏所有原先实现了这个接口的类。这些类不会包 含新的方法,而且再也通不过编译。所有的实现者都必须更新,要添加新的方法 。
这两个模式可以混合并重用一些实现代码,同时还可以实现多个接口 。System.Collections.CollectionBase就是这样的一个例子,它个类提供了一 个基类。你可以用这个基类你的客户提供一些.Net缺少的安全集合。例如,它已 经为你实现了几个接口:IList, ICollection,和IEnumerable。另外,它提供了 一个受保护的方法,你可以重载它,从而为不同的使用情况提供自己定义的行为 。IList接口包含向集合中添加新对象的Insert()方法。想自己更好的提供一个 Insert方法的实现,你可以通过重载CollectionBase类的OnInsert()或 OnInsertCcomplete()虚方法来处理这些事件:
public class IntList : System.Collections.CollectionBase
{
protected override void OnInsert( int index, object value )
{
try
{
int newValue = System.Convert.ToInt32( value );
Console.WriteLine( "Inserting {0} at position {1} ",
index.ToString(), value.ToString());
Console.WriteLine( "List Contains {0} items",
this.List.Count.ToString());
}
catch( FormatException e )
{
throw new ArgumentException (
"Argument Type not an integer",
"value", e );
}
}
protected override void OnInsertComplete( int index,
object value )
{
Console.WriteLine( "Inserted {0} at position {1}",
index.ToString( ), value.ToString( ));
Console.WriteLine( "List Contains {0} items",
this.List.Count.ToString( ) );
}
}
public class MainProgram
{
public static void Main()
{
IntList l = new IntList();
IList il = l as IList;
il.Insert( 0,3 );
il.Insert( 0, "This is bad" );
}
}