【UML】如何看Android的UML图

    UML图有不少类型,这里只讨论最重要也最经常使用的两种 - 类图和时序图。

1. 类图

    经过类图,咱们能够很容易的了解代码架构,理清模块之间的关系,html

    包括继承(Inheritance),实现(realization),依赖(dependency),组合(Composition), 聚合(Aggregation), 关联 (Association) 等等。编程

    下面就图中给出的7种关系一一解读。设计模式

    

1.1 Composition

    Compostion 是一种 Association 关系,但它更强调两个类之间总体和局部关系,它暗示两个类之间有着相同的生命周期,数据结构

    好比说图中的三个1.多线程

  •   W 是 ViewRootImpl的成员变量之一,ViewRootImpl 对象的构造函数里也构造了W,所以,当ViewRootImpl 析构时,W也被析构,他们的生命周期是一致的。
    public final class ViewRootImpl implements ViewParent,
            View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
      ...
      final W mWindow;
      ...
      
      mWindow = new W(this); //互相引用,因此当一个销毁时,另一个也没法存在。
    
    View Code
  • 一样相似的关系存在于 WindowManagerService 和 WindwoState 之间。

1.2  Realization

       Realization就是实现,在Java中体现为implements 一个接口类interface, 在标准的C++中没有明确的接口概念,但抽象类实际上起着和接口相似的功能,由于C++的Realization能够体现为继承一个抽象类。在Android 的C++代码中,有一个特殊的抽象类IInterface, 定义了PC接口类的一些基本方法。架构

1.3  Association

      有接口就会有引用,在UML中一根最普通的单向箭头便是引用(关联)关系。它的含义是,某个对象用到了一个其余对象的接口或属性。一般,Assocation 经过两种方式获取app

  •  依赖注入,经过构造函数或SetXXX()接口,好比说 WindowState 经过构造时传入的参数获取了对IWindow对象的引用
    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
               WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
               int viewVisibility, final DisplayContent displayContent)
    View Code
  • 间接获取,经过调用其余对象方法返回。
    mActivityManager = ActivityManagerNative.getDefault();
    View Code  

1.4 Android 的 IPC interface.

    C++和Java 的接口都只支持进程内的调用。为了支持专门用于跨进程的接口调用,Android 专门作了一些规定。异步

    凡是以IXXXX 定义的接口类都可以支持IPC(固然,进程内也能够调用IXXXX定义的接口)。ide

    当咱们在图中看到一个IXXX 接口类,咱们即可以认为这是一个进程的边界,他的实现端和调用端对象运行在不一样的进程里(至少是不一样的线程)。函数

    如上图中,IWindow的两端W对象 和 WindowState 对象就用不一样的颜色来标明它们分属于不一样的进程,W运行在应用程序的进程里,而WinState存在与System Server 进程里。

1.5 Aggregation

    聚合表达了两个类的从属关系,但和Composition不一样,他们的生命周期并不同。

    一个经典的例子就是工厂和车子,车子是工厂造出来的,工厂倒闭了,车子能够继续开,反之亦然。

    图中PolicyManager 和 PhoneWindow就是相似的关系。

1.6 Inherritance

    就是最多见的继承关系了。

    复杂的继承关系很难阅读和记忆,经过UML图则方便不少,你能够清楚到看出继承关系,同时可以理解继承的设计思想。

    好比说图中右上角,PhoneWindow 继承了Window 类,Activity 引用的是其基类Window的对象,但背后真正干事的是PhoneWindow对象, 由于Acitivy 用的Window类对象是PolicyManager构造出来的。经过这种方式,PhoneWindow的实现细节被PolicyManager 和 Window 基类隐藏起来,从而大大下降了应用程序(Activity) 改变的概率。

    这个正是设计模式里有名的工厂模式之一。

1.7  依赖

    依赖不一样于引用,依赖者和被依赖着之间没有直接的对象引用,一般是常量或静态方法的使用。

    好比图中,Activity使用了PolicyManager类的静态方法 makeNewWindow() 建立了PhoneWindow对象,咱们说Acitivy 依赖PolicyManager 这个模块,但它并无引用PoclicyManager的对象。

    依赖一般用一根单向虚线箭头表示。

2. 时序图

    经过时序图,咱们能够了解代码的调用流程, 并能够检查调用过程当中可能产成的潜在问题,如死锁等。

    时序图能够从两个方向去看,纵向和横向。

    纵向描述了一个对象在时间轴上所作的事情,一个方块经过表明一个函数的调用。

    横向则描述了各个对象之间的调用关系, 包括同步调用,异步调用,返回等等。

    此外,在时序图中,咱们能够给执行块赋予不一样的颜色,表明了他们分别运行在不一样的进程或线程里。

    下面就是一张时序图的例子,它描述了Android中一个System server 进程启动的过程, 图中的粉红色注释列举了从图中咱们能够获知的一些信息。

 
     刚才不是说从时序图中能看出死锁? 就这样同样图?夸张了吧! 没错,看看下面一个例子吧!
 
 

    这是一个很简单的例子,图中有两个线程,绿色是app线程,它经过调用MediaPlayer 对象的函数来控制播放器,这里它作了两件事,Start() 而后 Stop (). 而粉色部分表明Driver 线程,它经过回调函数告知Mediaplayer 一下底层的事件。也就是说Mediaplayer 是一个被两个线程同时引用的对象,是一个共享的资源。

    想固然的,咱们用了一把锁来保护它,防止他被同时使用产生冲突。因此,图中,绿色的app在Stop()时候首先拿到了锁。这时问题发生了,Stop()的过程可能会比较长,中途来了一个事件, 图中黄色注释的右方显示了这个状况,两个颜色的长条重叠在一块儿。这代表有资源冲突发生,也意味着潜在的死锁风险。咱们假设Stop()的最终目的就是要析构VideoDecoder 对象,但此时,VideoDecoder调用的eventHandler() 在另一个线程还没返回,理所固然的咱们须要等待它。不幸的是,这个时候死锁发生了,如图中红色注释所示。

    经过简单的画这么一个图,能够很轻易的分析出一个死锁的状况。那怎么解决它的,尽能够的避免图中不一样颜色的条块重叠在一块儿。看看下面的解决方案


     这回,咱们取消了锁的操做,经过添加一个新的线程(变成3个线程,3种颜色)Thread,将同步的调用变成异步,,交由Thread作后台处理。
     所以图中再也不有颜色块重叠(异步调用产生的重叠不算), Stop()和EventHandler都很快返回(异步调用), 从而消除了死锁的存在。
     这也是为何Andriod 设计了Looper, MessageQueue 和 Handler 的异步消息处理机制,并在Framework 中大量的使用,由于Android 是个极其复杂的多线程/多进程应用环境,基于锁的同步调用机制是难于保证彻底避免死锁的发生。

    这下赞成了吧,时序图对分析多线程的编程分析有很大的帮助。咱们应该在设计阶段尽量的用类图和时序图来帮助咱们避免一些常见的问题,帮助咱们得出一个尽量好的设计。

3.  怎样画Android UML 图?

    工具!必须依赖工具,市面上有太多的UML工具,你只须要找一款支持逆向工程的,即将代码转换成UML的数据结构,而后将类图或时序图一步步的绘制出来。

参考文章

http://www.cnblogs.com/samchen2009/p/3315999.html
相关文章
相关标签/搜索