首页 > 代码库 > UML之轻松入门(1)-类图

UML之轻松入门(1)-类图

     曾经看到过一篇blog,上面探讨了学习UML和学习设计模式的区别,同时提出了学习UML还不如学习设计模式的观点。自我感受是,UML和设计模式在本质上属于完全不同的两个方向。设计模式是一种被反复使用、多数人知晓的、代码设计经验的总结。它可以更容易让人理解而且保证了代码的可靠性,而UML则是一种模型化和可视化的一种语言。可以这么说,设计模式是一种方法,它让我们的代码更有层次感 。而UML则是一种表达,它让我们的代码更加形象化。通过UML我们不必太过关注代码,不必担心客户是否了解相关的语言知识,整体的架构和功能的分析和实现成为我们的主要任务。应此,学习UML和设计模式都是很必要的。
     UML是标准建模语言的简称,它是一个支持模型化和软件系统开发的图形化语言。为原件开发的所有阶段提供模型化和可视化支持。一般来说,软件开发可以分为5个阶段1.需求分析阶段,主要是根据客户的需求进行系统功能建模,每一个客户需求都是一个用例。2.分析,主要是考虑需要解决的问题,利用逻辑图和动态图等方式描述系统特征。3.设计,主要是将分析阶段扩展为解决方案。4.构造,主要是吧设计阶段的类转化为相应的代码。5.测试,对系统进行单元和协同测试,以验证系统是否符合要求。
     UML有3类主要的图,分别是静态图,动态图和物理图。其中静态图主要表示类、对象的结构和之间的关系。动态图表示在运行期间软件实体的变化。物理图则表示软件实体的不变物理结构,如源文件、2进制文件等。
     现在通过实例观察类图的用法:

     1.类的表示


     例如在java中我们定义了一个Person类
     
   public class Person {
     private String name;
     private int age;
     public int publicId;
     protected int className;
     public void setName(String name){
            this. name = name;
     }
     public String getName(){
            return this. name;
     }
   }

     这个类在UML图中的表示是

    

     从这个实例中我们看出:
1.类的组成:类名称写在第一排,类的属性写在第二排,类的方法写在第三排。+代表public-代表private#代表protected
2.类的属性:其格式为     (+|-|#)?(yourClassName):(type)     
3.类的方法:其格式为     (+|-|#)?(yourClassName/((params)?/)):(type)     和类属性稍有不同的是,可以传入参数,“:”后代表的是传参的类型

     2.类的关联


     类的关联大致包括3个方面继承包含另一个类的引用接口

     继承:


     在java中定义一个Man类,让它继承Person类

    public class Man extends Person {
     private int money;
     public int getMoney() {
            return money;
     }
     public void setMoney( int money) {
            this. money = money;
     }
   }

     在UML图中可以这么表示

    

     从这张图可以看出:我们可以用一个带空心三角形的符号来表示继承的关系。同时,箭头指向的类为超类箭头的源头为子类

     包含另一个类的引用


     在这里我们创建一个Woman类,它包含Man的一个引用。在实际生活中很多家庭主妇的钱都是老公赚的(除了女强人,哈哈)。因此,在Woman类中money属性的值是由Man的一个引用来决定的。代码实现如下:
    
   public class Woman {
     private Man myMan;
     private int money;
     public int getMoney(){
            this. money = myMan.getMoney();
            return this. money;
     }
     public void setMyMan(Man man){
            this. myMan = man;
     }
  }

    用UML图我们可以这么表示:

    

     从图中我们可以看到:当一个类拥有另一个类的引用时,应用带箭头的线表示,箭头指向为被引用的对象源头为引用者
     这里要注意箭头的不同,继承为三角形,而引用则不是。

     接口


     java中接口是实现多态的重要一环,也是封装不可缺少的一部分。在UML中对接口的使用也有特殊的表示:

    

     从图可以看出:UML中的接口用一个圆圈和一条直线表示。

     3.创建特殊的类


     在java中我们常需要创建一个接口来实现封装。我们也常需要创建一个抽象类来实现多态。有时候,我们也要用一个静态类作为一个静态常量的容器。下面我们一起学习如何在UML中表示这些特殊的类。
     

     接口类


     在java中我们定义一个Student接口,这个接口要实现write()和read()方法。

     public interface Student {
     public void write();
     public void read();
   }     

     这个接口在UML中的表示方法如下:

    

     从图中我们可以看出:可以用<<interface>>来表示一个接口类

     静态类


     我们在java中定义一个Math的静态类,其中定义PI的属性:     

     public class MathParams {
     static class Math {
            public static final double PI = 3.141592654;
     }
   }

     这个静态类,我们在UML中可以这么表示:

    

     从图中可以看出:可以用<<utility>>来表示一个静态类。

     抽象类


     在java中我们定义一个抽象Person类,这个Person类有两个方法,抽象的write()方法和具体的eat()方法(因为每个人都会吃,但不是每个人都会写字,呃...)。

     public abstract class PersonAbstract {
     public abstract void write();
     public void eat(){
            //...
     }
   }
 
     这个抽象类在UML中的表达方式是:

    

     从图中可以看出,抽象的类和方法都用斜体 表示。因为本人用的是VISIO开发工具,其默认是用斜体表示。还有另一种表示方法是在抽象的类和方法后加上{abstract}约束。而且这个“{}”不仅可以加"abstract",还可以添加自己的属性,如{name = "Lee",age = 13}。

     4.类图中的一些常用标记


    

     这三种表示方法差别并不大,所以在大多数时候只采用第一种方式就行了。最后一种方式可以表示:两个类是组合在一起的,即Woman的一个对象复制后,它对应的那个Man对象也会复制。当Woman的一个对象清空时,那么它对应的那个Man对象也会被清空。

     内部类是用一个圆圈中含有十字架加上一条线段组成(在VISIO中并未找到,还请了解的人相告)。

     在包含类的引用时,当包含的引用不止一条时,我们就需要用一个容器装载包含的引用,可能是Vector,也可能是其他的。这时,我们可以用关联类的表示:

    

     5.一个简单的应用


     这里是一个简单的二元树算法:
     首先,为了更加容易的理解算法,我们回顾一下Comparable接口Comparator接口。
     Comparable和Comparator都实现了比较的功能,不能的是:1.Comparable是java.lang包,而Comparator是java.util包中。2.Comparable接口需要绑定到一个指定的类上,而Comparator则不需要。因此,comparator更加灵活。3.Comparable需要重写comparaTo方法,且只需传入绑定的对象一个参数,而Comparator需要重写compare方法,需要传入比较的两个对象,两个参数。下面我们用比较两个字符串的长度来看看两中方法的差别:
     
     使用Comparable来比较两个字符串的长度:
   
  //通过实现Comparable接口来自定义比较的规则,实现compareTo方法
 public class MyComparable implements Comparable<MyComparable> {

     //这个例子实现比较两个字符串的长度
     private String compareString;
     MyComparable(String compareString){
            this. compareString = compareString;
     }
     
     //这里重写两个比较的规则
     @Override
     public int compareTo(MyComparable o) {
            // TODO Auto-generated method stub
            return this. compareString.length() - o.compareString.length();
     }
  }

     使用Comparator来比较两个字符串的长度:

     import java.util.Comparator;

   //实现Comparator接口无需绑定类,可实现动态排序
   public class Mycomparator implements Comparator<String> {

     @Override
     public int compare(String o1, String o2) {
            // TODO Auto-generated method stub
            return o1.length() - o2.length();
     }
   }

     了解了Comparable接口的用法后,我们来看简单的二元树的算法:

     public class TreeMap {

     TreeMapNode topNode = null;
     public void add(Comparable key,Object value){
            if( topNode == null)
                 topNode = new TreeMapNode(key,value);
            else
                 topNode.add(key,value);
     }
     
     public Object get(Comparable key){
            return topNode == null? null: topNode.get(key);
     }
   }

   class TreeMapNode {

     public static final int LESS = 0;
     public static final int GREATER = 1;
     private Comparable itsKey ;
     private Object itsValue;
     private TreeMapNode nodes[] = new TreeMapNode[2];
     
     public TreeMapNode(Comparable key,Object value) {
            // TODO Auto-generated constructor stub
            this. itsKey = key;
            this. itsValue = value;
     }
     public void add(Comparable key, Object value) {
            // TODO Auto-generated method stub
            if( itsKey.compareTo(key) == 0)
                 itsValue = value;
            else
                addSubNode(selectSubNode(key),key,value);
     }

     private void addSubNode( int node, Comparable key, Object value) {
            // TODO Auto-generated method stub
            if ( nodes[node] == null)
                 nodes[node] = new TreeMapNode(key, value);
            else
                 nodes[node].add(key, value);
     }
     private int selectSubNode(Comparable key) {
            // TODO Auto-generated method stub
            return ( key.compareTo(itsKey) < 0)? LESS: GREATER;
     }
     public Object get(Comparable key) {
            // TODO Auto-generated method stub
            if( key.compareTo(itsKey) == 0)
                 return itsValue;
            return getSub(selectSubNode(key),key);
     }
     private Object getSub( int node, Comparable key) {
            // TODO Auto-generated method stub
            return nodes[node] == null? null: nodes[node].get(key);
     }
     
   }

     下面我们用UML图来表示这个类:

    

     6.总结

     
     UML本来就是一个让代码更加形象的东东,应此不需要太过复杂。所以UML的内容最好比较简洁明朗,达到言简意赅的效果才是最好。

UML之轻松入门(1)-类图