4.2 类层次结构
Visual Studio 2005提供了几个用于描述类层次结构的可视化工具。这些工具也用于描述单独的类型,如类、结构和接口,这包括显示这些类型之间的关系,如继承关系等等。对类视图和对象浏览器都用新功能进行了升级。类关系图是在Visual Studio 2005中添加的强有力的对象建模工具。
4.2.1 类视图窗口
类视图窗口提供了对包括在当前解决方案中项目里的类型的可视化表示方法。展开项目并展开类节点就可以显示类层次结构。在类层次结构中的每一项都有具有很多有用命令的一个快捷菜单,例如,快捷菜单可以显示在一个类关系图中的类。“类视图”窗口现在就可以对被引用应用程序里的类进行显示,打开“项目引用”文件夹找到引用并查看它们包含的类。图4.10显示了“类视图”窗口,包括“项目引用”文件夹。如果“类视图”窗口被关闭了,可以从“视图”菜单里打开它。
图4.10 “类视图”窗口
“类视图”窗口有两个窗格:上部的窗格包含有类层次结构,而下部的窗格显示类层次结构中所选项的详细信息。在类视图窗口的顶部有4个图标:“类视图新文件夹”、“后退”、“前进”和“类视图设置”。在这些图标下边是搜索组合框,用于在类层次结构中搜索一个符号,这对于较大的类层次结构尤其有用。键入需要搜索的文本并按Enter键以启动一个搜索。包含搜索文本的某些部分的所有符号,如类、方法、字段和属性,都返回到“类视图”窗口中。
4.2.2 对象浏览器
对象浏览器是相对于“类视图”窗口的另一种选择。对象浏览器显示当前项目、被引用的应用程序和系统库的类层次结构。如果对象浏览器不可见,可以从“视图”菜单打开它。图4.11显示了对象浏览器窗口。
图4.11 对象浏览器
4.2.3 类关系图
Visual Studio 2005引入了类关系图。类关系图由“类设计器”创建,“类设计器”是Visual Studio 2005的一个内部组件。开发人员可以通过类关系图为面向对象的应用程序建模,这一工具将来肯定会不断发展,最终成为开发人员的至爱。对于我来说,它已经成为我在Visual Studio中最常用的工具之一。类关系图为类型和类型层次结构提供了一种可视化表达方式。值得注意的是,类关系图不是静态的,开发人员可以添加新类型,创建新关系,插入成员,删除成员等等。类关系图是和应用程序的源代码同步的,对在类关系图中建模的类型的改变会被立即反映到代码中。相反,对源代码的改变也会立即显现在相关类关系图中。因此,应用程序和关系图始终保持同步。修改设计文档是类关系图的基本好处之一。在开始实现项目之后,项目文档都消失到哪去了?这是一个折磨着面向对象应用程序开发人员的共同问题。对于很多应用程序来说,原始设计文档是不可用的或是在软件发展时没得到更新的。设计文档常常很快就变得陈旧,并且在实现阶段不久就消失了。类关系图有助于更新这些重要的文档,包括对原始设计的改变。相反地,类关系图可以作为映像保存起来用以保留设计的一个快照。通过类设计,设计和实现阶段真正实现了循环,这将转化为开发得更好的应用程序。这也使得应用程序的维护变得更加轻松。
类关系图为应用程序提供了一个高层次的远景,这对于应用程序的整个生命周期都是有益的。这对于具有上百个类和许多个关系的复杂系统来说尤其有用,在这样的环境下检查代码是一个乏味、耗时的过程。它同时没有失去通常只有一个应用程序大纲视图才能提供的清晰理解。类关系图提供了一个概览,如果需要的话还可以提供一定的自省信息。这些信息对进行应用程序维护的程序员来说具有重要价值。对于任何用Visual Studio来进行产品维护的人来说,类关系图代表了一个新的起点。
整个类层次结构都可以呈现在类关系图中,但是由开发人员控制有多少信息可以在类关系图中呈现出来。你可以查看一个类、多个类型或者在类关系图中的任何东西,这取决于开发者的判断力。除此之外,多个类关系图还可以被添加到组相关的类型里,或简单地减少在任何特定关系图里信息的数量。你可以查看关系图里的所有类型:类、结构和接口。也可以查看类型之间的关系,如继承和关联。
在Visual Studio 2005中,可以通过几种方法来创建一个类关系图。一种方法是在“项目”菜单里选择“添加新项”,然后在“添加新项”对话框里选择“类关系图”,在编辑框为类关系图命名(类关系图文件会自动以.cd为文件扩展名)。也可以从“解决方案资源管理器”或“类视图”窗口打开一个新的类关系图。在“解决方案资源管理器”中,打开一个项目或源文件的快捷菜单,然后选择“查看类关系图”,这将创建一个包含在该项目或源文件中所有类的新的关系图。在“类视图”窗口,打开一个项目名或类的快捷菜单,然后选“查看类关系图”。
类关系图有一个表面。有几个方法可以在这个表面上添加已经存在的或新的类型,如下所示:
l 从“类视图”窗口或“对象浏览器”拖一个类型到类关系图表面。
l 从“解决方案资源管理器”拖一个文件到类关系图表面。
l 从“类设计器”工具箱添加一个新类型。
添加到类关系图表面的类型以图形来表示。
图4.12展示了表面有一个类的类关系图,这个单个类被包含在一个图形里。该图形有一个标题和一个详细信息窗格。单击图形标题上的类标签可以对类进行重命名,双击类标签可以查看相关的源代码。图形上有一个扩展按钮或折叠按钮,扩展按钮是两个向下的箭头以显示类型的详细信息,折叠按钮是两个向上的箭头以隐藏类型的详细信息。根据是否扩展或折叠详细信息在扩展按钮和折叠按钮之间进行切换。
图4.12 包含单个类的类关系图
可以从一个类关系图中移除类型。选择代表要移除类型的图形并从类标题打开快捷菜单,选择“从关系图中移除”,类就从关系图中移除了,但仍然保留在程序中。“删除代码”选项就不一样了,该选项不但将类从类关系图中删除,而且还在项目中将其删除。从关系图中删除一个类的更简便的方法是简单地选择要删除的类型,然后按Delete键。
类的详细信息显示类的成员,成员通过类型来组合,字段、方法、属性和其他成员类型都在这里组合。每个组都可以折叠或扩展。通过快捷菜单,成员可以被重构、删除、复制、粘贴等等。成员也可以在“类详细信息”窗口查看,如图4.13所示。如果“类详细信息”窗口不可见,可以从在类关系图里的任意形状的快捷菜单显示它。
图4.13 “类详细信息”窗口
在“类详细信息”窗口里,你可以查看、更改、或添加一个新成员到类里。你可以更改一个类型的名称、类型或可访问性。“隐藏”选项隐藏或显示在类关系图中的一个成员。类标题的快捷菜单有“显示所有成员”命令,该命令显示所有的成员,包括任何隐藏成员。
“类详细信息”工具箱有5个按钮。“新建成员”按钮添加一个方法、属性、字段、事件、构造函数、析构函数或常量到一个类。“定位到方法”按钮在“类详细信息”窗口中选择该方法类别,这对于有很多成员的大类来说很有用。最后的3个按钮分别定位到属性、字段和事件。
类关系图工具箱
类关系图有一个特殊的工具箱,如图4.14所示。在工具箱上的按钮用来向应用程序和类关系图添加新类型。可以添加一个新的类、枚举、接口、抽象类、结构和委托。双击相关的按钮向应用程序添加新类型,添加之后,新类型就会显示在类关系图上。除此之外,还可以从工具箱拖动相关按钮到类关系图表面上来添加新类型。当一个新类型被添加的时候,会显示一个“新类型”对话框(图4.15中是“新接口”对话框,因为添加的是一个接口。——译者注),类型的名称、可访问性和文件名都可以在这个对话框输入。
在工具箱中的添加新类型按钮之后,出现的是继承和关联按钮。继承按钮创建一条连接基类和派生类的继承线。关联按钮创建一条定义嵌入类和所有类之间的关系的关联线。注释按钮是工具箱中的最后一项,用于向类关系图添加注释。
图4.14 类关系工具箱 图4.15 “新接口”对话框
4.2.4 继承
继承在类关系图中是可视的,继承线描述了基类型到派生类型的关系。对System.Object和 System.ValueType的隐式继承不会显示在类关系图中。图4.16显示的是在类关系图中的类继承。在图中,XClass继承了ZClass。继承线是从派生类出发指向基类的向量,删除继承线可以消除继承关系。此外,也可以从快捷菜单删除继承线,具体做法是打开继承线上的快捷菜单然后选择“删除代码”。
可以在类关系图中定义新的基类和派生类。在工具箱中选择继承线。从派生类拖一条继承线到基类。前提是基类和派生类已经在类关系图中。如果基类不在类关系图中,从“类视图”窗口拖动该类到类关系图中的派生类图形中,这不仅创建了一个继承关系,还同时向类关系图添加一个基类。
接口继承和类继承同样也显示在类关系图中。用继承线向一个类型中添加接口继承。为了完全实现该接口,类关系图为在派生类中的接口的每个成员添加分支线。开发人员可以在代码编辑器中用适当的实现来替代这些分支线。接口继承并不描述为继承线,而是显示为一个在派生类顶上的棒棒糖形状。如图4.17所示,ZClass继承IA接口。可以用接口标签上的快捷菜单来改变继承是如何实现的,这包括是隐式还是显式实现接口。
继承线和关联线等关系线可以改道。只需单击该线并拖动鼠标就可以改道。线可以多次改道。图4.18显示了一条改道的继承线。拖动该线的端点对类图形上的关系线进行重新配置。当鼠标指针定位在关系线的端点上时,指针变成一个十字。关系线的快捷菜单可以对关系属性进行隐藏、改道、删除或显示。
类关系图可以定位基类或派生类。打开类图形标题上的快捷菜单,“显示基类”命令在类关系图中定位类型的基类。如果基类没有显示出来,则被添加到类关系图中。“显示派生类”命令用于选择派生类型。
图4.16 在类关系图中的类继承 图4.17 在类关系图中的接口继承
图4.18 改道的继承线
4.2.5 关联
关联线定义了一种“有一个”关系,即一个类拥有另一个类。类可以作为一个属性嵌入到其他类中。图4.19显示在类关系图中的一个关联关系。在图中,XClass类拥有YClass,YClass作为一个属性嵌入到XClass中。关联线和继承线在外观上稍有不同。
图4.19 关联关系
在类关系图工具箱里选择相应的关联线来创建一个新关系。类和接口都可以嵌入。将关联线从所有类型拖到嵌入类型,在所有类中为嵌入类创建一个属性。之后就可以切换到代码编辑器并实现该属性,返回一个嵌入类型的实例。当关联线是可见的时候,嵌入成员就不会显示在类图形里的类详细信息窗格中。如果你愿意,可以显示嵌入成员并隐藏关联线。打开关联线的快捷菜单并选择“作为属性显示”命令。反之,打开快捷菜单并选择“作为关联显示”。
4.2.6 类关系图演练
以下的演练步骤是对类关系图(尤其是对创建新类型和关系)的一个示范。
1. 创建一个新的类库。在Visual Studio 2005中,从“文件”菜单选择“新建”子菜单来创建一个新项目。也可以通过在标准工具栏中单击“新建项目”来做到这一点。在C#项目中选择“类库”模板,并给项目命名为“Personnel”。
2. 添加一个类关系图到项目。打开“项目”菜单并选择“添加新项”菜单项,从“添加新项”对话框添加一个类关系图。该类关系图被命名为“Employee”。
3. 用类关系图工具箱添加一个新接口。命名该接口为“IEmployee”,其他用默认选项。
4. 用类关系图工具箱添加一个新抽象类,命名为“Employee”。
5. 用类关系图工具箱添加另一个类,命名为“HourlyEmployee”。
6. 用类关系图工具箱添加一个新结构,命名为“Name”。结构在类关系图中表示为一个圆角方形。
从“类详细信息”窗口为IEmployee接口添加三个成员(见图4.20)。EmployeeInfo方法返回一个字符串。Age属性是一个整数用于读取和设置一个雇员的年龄。最后,Fullname属性是“Name”类型并用于获取“Employee”的名字。
图4.20 IEmployee接口的详细信息
Employee类应该继承和实现IEmployee接口。在类关系图工具箱中选择继承线,将继承线从Employee类拖到IEmployee接口。接口成员现在显示在Employee类的类详细信息中。此外,Employee类给出了接口成员的初步实现:
public abstract class Employee : IEmployee
{
#region IEmployee Members
public int Age
{
get
{
throw new Exception(
"The method or operation is not implemented.");
}
set
{
throw new Exception(
"The method or operation is not implemented.");
}
}
// Partial listing
Employee类的派生类型必须具有计算薪水操作。为Employee类添加一个CalculatePay抽象方法,该方法返回一个十进制数。在Employee类的标题打开其快捷菜单,选择“添加”子菜单和“方法”菜单命令,为新方法命名为“CalculatePay”。在“类详细信息”窗口设置十进制数作为返回类型。该方法应该设置为抽象的。打开CalculatePay方法的快捷菜单并修改“继承修饰符”为abstract(抽象)。然后系统显示一个消息框要求你对这一修改进行确认,选“确定”。
HourlyEmployee类应该继承Employee类。这一关系用继承线来创建,具体做法是:将继承线从HourlyEmployee类拖到Employee类。
最后,为HourlyEmployee类添加一个Pay方法。Pay方法只有一个参数,就是工作的小时数。在“类详细信息”窗口,扩展Pay方法的行来打开“添加参数”项,选择“添加参数”行并输入“Hours”作为参数名,修改类型为十进制数。添加一个HourlyRate属性到该类以使其完整,该属性也是十进制数类型的。
Personnel应用程序的最终类关系图如图4.21所示。
图4.21 Personnel库的类关系图
以下代码由类关系图创建。创建的函数是很粗略的,接下来只需要实现这些粗略的函数。
public interface Iemployee
{
int Age
{
get;
set;
}
Name Fullname
{
get;
set;
}
string EmployeeInfo();
}
public struct Name
{
public string FirstName
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
public string LastName
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
}
public abstract class Employee : IEmployee
{
#region IEmployee Members
public int Age
{
get
{
throw new Exception(
"The method or operation is not implemented.");
}
set
{
throw new Exception(
"The method or operation is not implemented.");
}
}
public Name Fullname
{
get
{
throw new Exception(
"The method or operation is not implemented.");
}
set
{
throw new Exception(
"The method or operation is not implemented.");
}
}
public string EmployeeInfo()
{
throw new Exception(
"The method or operation is not implemented.");
}
#endregion
public abstract decimal CalculatePay();
}
public class HourlyEmployee : Employee
{
public decimal HourlyRate
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
public override decimal CalculatePay()
{
throw new Exception(
"The method or operation is not implemented.");
}
public void Pay(decimal Hours)
{
throw new System.NotImplementedException();
}
}
4.2.7 “错误列表”窗口
“错误列表”窗口是Visual Studio 2005的一个新功能,它显示编辑和编译错误、警告和一般信息。每个消息类型都被分配一个惟一的图标,例如,错误消息就表示为一个带×的红色圆圈。如果存在编译错误,编译程序的时候自动会显示“错误列表”窗口(见图4.22)。也可以从“视图”菜单显示“错误列表”窗口。
图4.22 “错误列表”窗口
“错误列表”窗口显示不同类别的消息,“错误”、“警告”和“一般”按钮隐藏或显示特定类别的消息。“错误列表”按钮也显示各种类别消息的数量,对于每个错误都显示错误号、描述、错误发生位置。在错误列表中双击一个错误消息会跳到相关的源代码。此外,还可以用列标题来对错误列表排序,列标题可以被拖动以改变列的顺序。v