`

利用UML类图设计Java应用程序详解(一)

 
阅读更多
UML已成为面向对象设计的标准图形化工具,在UML定义的各种图中,本文只涉及类图。Java应用程序由许多类所构成,类图的设计与实现,是Java实现面向对象应用程序的核心。本文通过一个具体的应用程序的设计与实现过程,详细说明了利用UML类图设计Java应用程序,使得开发过程标准化、可视化,代码编程简单化。
  在类图中,类被描述为带有三层的盒子。
  
  顶层为类名,一般用加粗字体表示。如果类是抽象的,其名称用斜体表示;如果类是接口,则在类名上方标注<<interface>>。
  中间层包含类的属性(或变量),底层包含类的方法。与类名相似,如果方法是抽象的,那么它的名称也用斜体表示。
  我们要设计的应用程序CDrawApp应用程序在基于字符的网格上画点、框和文本串,该应用程序涉及到Java面向对象的许多概念与应用方法,非常系统、全面,在您仔细研读后,定能迅速掌握UML类图,并将其应用到实际的Java应用程序开发过程中。为减少代码长度,让程序简单易懂,这里使用Java控制台窗口显示程序运行结果。该程序总共由10个大类组成,以下分别介绍。
  一、Point类
  在CDrawApp程序中定义的第一个类是Point类,该类用于通过x和y坐标在网格上标识一点。其类图设计为:
  
  在该类中,有2个成员变量x和y,类图中,“-”表示变量或方法为private,“+”表示public,“#”则表示protected。该类定义了三个不同的构造函数,这是重载(overload)的例子。
  接着该类设计了7个访问方法。getX()和getY()方法分别返回一点的x和y坐标。SetX()和setY()方法根据参数xValue和yValue的值设置这些坐标的值。两个add()方法通过被访问点的坐标加上一个值来建立一个新的Point对象。New运算符建立类的新实例。它后面紧跟着初始化新生成实例的构造函数。toString()
  方法返回类String的一个对象,该对象用一个有序对来描述一个点。
  依据设计的类图,其Java实现代码为:
  // Point.java
  public class Point {
  // Variable declarations
  private int x;
  private int y;
  //Method declarations
  public Point() {
  x = 0;
  y = 0;
  }
  public Point(int xValue, int yValue) {
  x = xValue;
  y = yValue;
  }
  public Point(Point p) {
  x = p.getX();
  y = p.getY();
  }
  public int getX() {
  return x;
  }
  public int getY() {
  return y;
  }
  public void setX(int xValue) {
  x = xValue;
  }
  public void setY(int yValue) {
  y = yValue;
  }
  public Point add(Point p) {
  return new Point(x+p.getX(), y+getY());
  }
  public Point add(int i,int j) {
  return new Point(x+i,y+j);
  }
  public String toString() {
  return new String("("+String.valueOf(x)+","+String.valueOf(y)+")");
  }
  }
  二、CGrid类
  CGrid类用于定义指定大小的字符网格。它提供基本方法集,通过加入到这些方法中的其它类来得到扩展。该类的类图为:
  
  CGrid类声明3个变量:width、depth和grid[][]。width和depth 变量用于指定grid[][]的水平和垂直尺寸,grid[][]是保存网格字符的字符数组的数组。
  CGrid中的变量声明为protected,这就规定了它们只能在声明它们的包中和CGrid的任何子类中访问。
  CGrid类只有一个单一构造函数,它设置width和depth的值,分配grid[][]数组,然后调用blankGrid()以空格为grid[][]赋值。
  CGrid有4种访问方法。blankGrid()方法只是简单地用空格字符来调用
  fillGrid()。fillGrid()方法把grid[][]的每个元素都设置为ch参数。GetCharFrom()方法用于找出网格中给定位置的字符。SetCharAt()用于把网格中一点设置成特定字符。
  在GetCharFrom()和SetCharAt()方法中使用Point类来定义它们的参数,这是类与类之间关联的例子,我们稍候讨论。
  根据以上类图,CGrid类的原代码为:
  // CGrid.java
  public class CGrid {
  // Variable declarations
  protected int width;
  protected int depth;
  protected char grid[][];
  // Method declarations
  public CGrid(int widthValue,int depthValue) {
  width = widthValue;
  depth = depthValue;
  grid = new char[depth][width];
  blankGrid();
  }
  public void blankGrid() {
  fillGrid(' ');
  }
  public void fillGrid(char ch) {
  for(int j=0; j<depth; ++j)
  for(int i=0; i>width; ++i)
  grid[j][i]= ch;
  }
  public void setCharAt(char ch,Point p){
  grid[p.getY()][p.getX()] = ch;
  }
  public char getCharFrom(Point p) {
  return grid[p.getY()][p.getX()];
  }
  }
  三、CGObject类
  CGObject类是抽象类的例子,它通过abstract方法来限制其子类的行为。Abstract方法必须由非abstract子类实现。其类图设计如下:
  
  CGObject类用于定义在网格上显示的对象的一般行为。它有两个变量:location和drawCharacter。Location变量的类型是Point,用于在网格上指定一个对象所在的点。DrawCharacter变量用于画对象的字符。
  CGObject有三个方法,而没有构造函数。因为abstract类没有完整定义,所以它没有构造函数,也没有对象实例。
  第一个方法addToGrid()不是abstract类型的。它以类PrintCGrid的对象作为参数,调用PrintCGrid类的addCGObject()方法,把this对象加到网格中。this关键字指当前对象。用addToGrid()方法调用CGObject类的子类的对象,这些对象加到类PrintCGrid的对象中。
  CGObject的其它两个方法都用abstract关键字声明。这意味着,这两个方法在能够由CGObject类的非abstract子类使用前必须被覆盖。覆盖方法必须拥有与anstract方法相同的名字、参数和返回值。Display()方法用于再网格上显示类PrintCGrid的一个对象。Describe()方法用于显示网格对象的描述。
  CGObject类的代码为:
  // CGObject.java
  public abstract class CGObject {
  // Variable declarations
  public Point location;
  public char drawCharacter;
  // Method declarations
  public void addToGrid(PrintCGrid grid) {
  grid.addCGObject(this);
  }
  public abstract void display(PrintCGrid grid);
  public abstract void describe();
  }
  四、PrintCGrid类
  PrintCGrid类是CGrid类的子类,它定义了允许把对象加到网格中的附加变量和方法。它也提供了显示网格的方法。PrintCGrid类的类图如下图所示:
  
  PrintCGrid类与CGrid类的关系是子类与父类的关系。在类图中用实线与空心箭头从子类指向父类表示。
  
  由于PrintCGrid类是CGrid类的子类,PrintCGrid类声明中必须添加extends子句。这意味着在CGrid种定义的所有变量和方法在PrintCGrid中都能得到。这就是继承的强大功能,也是面向对象语言的主要特征之一。PrintCGrid使用CGrid作为一个基础,在这个基础上增加其它网格显示的变量和方法。
  PrintCGrid类的原代码为:
  import java.lang.System;
  // PrintCGrid.java
  public class PrintCGrid extends CGrid {
  // Variable declarations
  protected CGObject displayList[];
  protected static final int maxObjects = 100;
  protected int numObjects;
  // Method declarations
  public PrintCGrid(int x,int y) {
  super(x,y);
  numObjects = 0;
  displayList = new CGObject[maxObjects];
  }
  public void addCGObject(CGObject obj) {
  if(numObjects < maxObjects) {
  displayList[numObjects] = obj;
  ++numObjects;
  }
  }
  public void deleteCGObject(int index) {
  if(index < numObjects && numObjects > 0) {
  for(int i = index; i < numObjects -1 ; ++i)
  displayList[i] = displayList[i+1];
  --numObjects;
  }
  }
  public void deleteLastObject() {
  if(numObjects > 0) --numObjects;
  }
  public int getNumObjects() {
  return numObjects;
  }
  public CGObject getObject(int index) {
  return displayList[index];
  }
  public void clearGrid() {
  numObjects = 0;
  }
  public void drawGrid() {
  blankGrid();
  for(int i = 0; i < numObjects ; ++i)
  displayList[i].display(this);
  }
  public void displayGrid() {
  for(int i=0;i<depth;++i)
  System.out.println(String.valueOf(grid[i]));
  }
  public void displayRow(int row) {
  System.out.print(String.valueOf(grid[row]));
  }
  public void show() {
  drawGrid();
  displayGrid();
  }
  }>
  在以上代码中,PrintCGrid声明3个变量:displayList[]、maxObjects和numObjects。这些变量都声明为proceted,从而把对它们的访问限制在一个包中和PrintCGrid的子类中。
  DisplayList[]变量是类CGObject(见以下类的介绍)的数组。但这并不意味着该数组包含作为类CGObject实例的对象。这是不可能的,因为CGObject是抽象的。把DisplayList[]声明成类CGObject的数组的目的,是允许该数组包含CGObject类的子类的对象。一般来说,如果一个变量声明成类X,那么可以把该变量赋值为X的子类的对象。
  MaxObjects变量声明成static并且final。使用static修饰符声明的变量,它们被作为一个类实例的所有对象公用,不会被每个实例复制,静态变量又成为类变量。没有被声明成静态的变量是实例变量,对作为一个类的实例的每个对象进行复制。
  Final修饰符用于把变量标识成常量。用final修饰符声明的变量必须在声明时进行初始化,不能再声明之外的任何地方赋值。MaxObjects常量初始化为100,表示可以加到displayList[]中的对象的最大数目。
  NumObjects变量用于统计加到网格的displayList[]中的对象实际数目。
  PrintCGrid有一个构造函数。该构造函数有两个参数:x和y,它们表示网格的水平和垂直方向的尺寸。构造函数调用super()方法,并把这两个变量当着变元传递过去。Super()方法是构造函数调用语句的一个例子。它以x和y作为变元调用PrintCGrid的父类(即CGrid类)的构造函数。CGrid的构造函数初始化其width和depth变量,分配grid[][]数组,并用空格给该数组元素赋值。CGrid的构造函数运行完后,PrintCGrid的构造函数继续把numObjects设置为0,并分配displayList[]数组。
  PrintCGrid提供10个访问方法。AddCGObject()方法把对象加到displayList[]数组中。DeleteCGObject()方法删除位于指定索引位置的对象。所有的后续对象都向前移动,以填充被删除对象留下的空缺。DeleteLastObject()方法通过简单地把numObjects减1来删除最后一个对象。
  GetNumObjects方法返回displayList[]中的对象数目。GetObject方法返回displayList[]中指定位置的对象。clearGrid()方法通过把numObjects设置为0去清除所有对象。
  DrawGrid()方法使用从CGrid类继承的方法清空网格,然后调用displayList[]中每个对象的display()方法。
  displayGrid[]方法在控制台窗口中显示每一行网格。它是继承的例子。Grid[][]数祖在CGrid类中定义,由PrintCGrid所继承。它由CGObject类的所有子类的drawGrid()方法和display()方法更新。PrintGrid()类用它来在控制台窗口中打印字符。
  ValueOf()方法用于displayGrid()方法中,它是String 类的静态方法。它把字符数组转换成String对象。静态方法类似于静态变量,它整体上应用于类,而不是作为类实例的各个对象使用。由于面向对象,静态方法只能访问静态变量。所有静态方法都是定局的,不能被覆盖。
  DisplayRow()方法在控制台窗口上显示一行网格,show()方法把drawGrid()和displayGrid()方法组合成一个方法。
  五、BorderPrintCGrid类
  BorderPrintCGrid类是PrintCGrid类的子类,它进一步扩展了CGrid类。它增加了生成类PrintCGrid对象的边界的变量和方法。类图见如下所示:
  
  BorderPrintCGrid类有四个私有变量:useBorder、borderCharacter、horizEdge和vertEdge。UseBorder是boolean类型的变量,它决定边界是否应该显示。BorderCharacter为用于显示边界的字符。HorizEdge和vertEdge用于显示边界的水平和垂直边界的String对象。
  BorderPrintCGrid类有两个。第一个构造函数没有参数。它调用PrintCGrid类的构造函数构造一个75字符宽20行高的网格,其边界字符为*。SetBorderDefaults()方法用于初始化BorderedPrintCGrid类的变量。第二个构造函数类似于第一个构造函数,但它提供了直接指定网格尺寸及边界字符的功能。
  BorderPrintCGrid类提供4个访问方法。SetBorderDefaults()方法使用enableBorder()方法和setBorderCharacter()方法初始化BorderedPrintCGrid类的变量。enableBorder()方法把useBorder设置成true或false。setBorderCharacter()方法设置displayGrid()方法所用的borderCharacter、horizEdge和vertEdge变量。
  BorderedPrintCGrid类是PrintCGrid的子类,其类图关系表示为:
  
  displayGrid()方法覆盖PrintCGrid类的displayGrid()方法。通过重新定义该方法以满足自己的需要。其中的super语句,将调用PrintCGrid.displayGrid()。
  该类的实现代码为:
  // BorderedPrintCGrid.java
  public class BorderedPrintCGrid extends PrintCGrid {
  // Variable declarations
  private boolean useBorder;
  private char borderCharacter;
  private String horizEdge;
  private String vertEdge;
  // Method declarations
  public BorderedPrintCGrid() {
  super(75,20);
  setBorderDefaults('*');
  }
  public BorderedPrintCGrid(int x,int y,char ch) {
  super(x,y);
  setBorderDefaults(ch);
  }
  private void setBorderDefaults(char ch) {
  useBorder = true;
  setBorderCharacter(ch);
  }
  public void enableBorder(boolean toggle) {
  useBorder = toggle;
  }
  public void setBorderCharacter(char ch) {
  borderCharacter = ch;
  char border[] = new char[width+2];
  for(int i=0;i<width+2;++i) border[i] = borderCharacter;
  horizEdge = new String(border);
  vertEdge = String.valueOf(borderCharacter);
  }
  public void displayGrid() {
  if(useBorder) {
  System.out.println(horizEdge);
  for(int i=0;i>depth;++i) {
  System.out.print(vertEdge);
  displayRow(i);
  System.out.println(vertEdge);
  }
  System.out.println(horizEdge);
  }else super.displayGrid();
  }
  }
  到这里,我们的程序设计与实现已完成将近一半。我们用UML类图分析了5个类,但这些类之间是如何相互作用而构成我们的应用程序呢?现在我们回过头来分析前面5个类之间的相互关联。首先我们分析继承概念在UML类图中的表示。
  
  通过UML类图中的各类之间的继承关系表示法,我们清楚地知道,CGrid是超类,PrintCGrid是CGrid的子类,BorderedPrintCGrid是PrintCGrid以及CGrid的子类。
  在Java类的代码实现中,一定要用相应的extends语句来表示实际的继承关系。
  一般类与类之间的关系我们可以用关联来表达。如在类CGrid中,在GetCharFrom()和SetCharAt()方法中我们使用了Point类来定义它们的参数,这是类CGrid对Point类的引用。类CGrid可以引用多个Point对象,因此,在多重性的概念中,表示该类CGrid可以与多个Point对象关系。
  
  在UML类图中,我们用一条实线表示这种关联为依赖关系,通过开叉的箭头表示是CGrid类引用Point类。箭头上方的0..*表示可以与多个对象关联。如果是0..1表示可以与1个对象关联;如果是1表示必须与1个对象关联;如果是1..*表示必须与至少1个对象关联。
  同样,在PrintCGrid类中,在其变量申明中,有对CGObject的引用,并且也是多重引用。其UML类图关系可以表示为:
  
  因此,以上5个类之间的相互关系,用UML类图关系可以清楚地表示为:
  
  本部分说明了5个类的UML类图表示、UML类图关系以及相应的Java实现代码。余下内容见第二部分。
分享到:
评论

相关推荐

    利用UML类图设计Java应用程序详解.doc

    利用UML类图设计Java应用程序详解.doc

    利用UML序列图设计Java应用程序详解

    要利用UML设计Java应用程序,仅仅使用类图来描述这些静态关系,利用可视化工具,要实现Java应用程序的代码自动生成,是远远不够的。我们还必须描述各种类相互之间的协作关系、动态关系,如时间序列上的交互行为。...

    利用UML序列图设计Java应用程序详解 

    要利用UML设计Java应用程序,仅仅使用类图来描述这些静态关系,利用可视化工具,要实现Java应用程序的代码自动生成,是远远不够的。我们还必须描述各种类相互之间的协作关系、动态关系,如时间序列上的交互行为。...

    抽象工厂模式uml类图

    java设计模式 抽象工厂模式详解 一张图让你彻底明白抽象工厂模式

    java多线程设计模式详解(PDF及源码)

    通过程序范例和UML图示来一一解说,书中代码的重要部分加了标注以使读者更加容易理解,再加上图文并茂,对于初学者还是程序设计高手来说,这都是一本学习和认识JAVA设计模式的一本好书。(注意,本资源附带书中源...

    Java设计模式

    Java设计模式详解,包含设计模式概述、适用性范围、参与者、uml类图、源码实例。由疯狂Java联盟整理提供

    人事面试100问及Java面试文档资料.zip

    UML类图详解.mht 中兴SQL题目.doc 中兴面试--公共部分.doc 人事面试100问.doc 你一定要给我记住啊.docx 好多不懂的Servlet以及Jsp.doc 学习笔记.doc 实践50.doc 深圳信狮职业培训学校java面试题.doc 第2章 递归与...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    本书为中南大学精品教材立项项目,分为上下两篇共21章,涵盖了面向对象技术中Java开发环境配置、程序设计基础、面向对象原理以及UML的知识。本书使用的开发环境是JDK 1.6+Eclipse 3.3+Rational Rose 2003,逐步引领...

    JAVA面试资料全集

    这里提供了各打公司的JAVA面试资料和许多的高科技技术UML类图详解

    高级Java软件架构师学习计划

    面向对象程序设计与编码 Java流操作和文件系统 Java图形用户界面编程 异常处理与事件响应 Java基础类库与中期项目实战 Java多线程编程、网络编程 项目实战 J2EE中级 数据库基础与linux操作系统 JDBC程序...

    java基础案例与开发详解案例源码全

    2.3.3 开发Java第一个程序21 2.3.4 Java代码中的注释23 2.3.5 常见错误解析24 2.4 Java类库组织结构和文档27 2.5 Java虚拟机简介28 2.6 Java技术两种核心运行机制29 2.7 上机练习30 第3章 3.1 变量32 3.1.1 什么是...

    疯狂JAVA讲义

    2.1.3 面向对象程序设计简介 27 2.1.4 面向对象的基本特征 28 2.2 UML(统一建模语言)介绍 29 2.2.1 用例图 30 2.2.2 类图 31 2.2.3 组件图 33 2.2.4 部署图 33 2.2.5 顺序图 34 2.2.6 活动图 34 2.2.7 ...

    asp.net知识库

    NET2.0系列介绍(一).NET 2.0 中Web 应用程序主题的切换 ASP.NET 2.0 中Web 应用程序主题的切换 2.0正式版中callback的一些变化+使用示例(ASP.NET 2.0) Server Side ViewState 在服务器端存贮ViewState (ASP.NET...

    UML统一建模语言初学

    类图详解: 1)构成形式:举一个例子:2)内部类: 我们使用诸如下边的方式表示内部类,定义在方法区例如:3)访问描述符: 对于Java,我们用如下的符号表示访问描述符: 我们在下图详细说明了各个访问描述符的...

Global site tag (gtag.js) - Google Analytics