移动架构师第一站UML建模
回想一下自己的Android生涯已经经历过N多个年头了,基本都是在编写业务代码,都知道35岁程序员是一个坎,当然如果有能力能做到Android架构师的职位其生命周期也会较长,毕境不是人人都能轻易做到这个岗位的,而在我的职位生涯中“Android架构师”一直是想做为一个自己前进的动力,但是一直都是空有其想法,木有实际行动,而这个博客专栏也已经创建多年了,但是还是0沉淀,所以接下来痛定思痛,一点点来打造自己的架构梦。
首先得要系统的复习UML相关的东东,架构图在实际做架构中是必不可少的,而这项技能也早已经忘得差不多了,为了完美性,这里集中再复习一下它。这里采用的绘图工具是用的PowerDesigner,如下:
我想应该搞程序的木有人不知道它了,很强大,主要是它可以对其进行Java代码生成及逆项,但是它只有Windows版的,而我的个人电脑是个MAC。。所以当然得装个虚拟机,这里推荐一个MAC上我在用的虚拟机“Paralles Desktop”:
在它上面装了个Wind8,对于学习已经绰绰有余了,另外该模拟器有一个比较好的功能就是说可以将系统装在一个扩展盘上,由于我的MAC是15年款的,硬盘容量只有256G容量比较小,要是装在MAC上内置的盘里有点浪费空间,毕境该模拟器只是偶尔用,于是乎我就将其装到了外接盘里了,非常之方便。
UML概念【了解】:
定义:
是统一建模语言,是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。
作用:
1、帮助开发团队以一种可视化的方式理解系统的功能需求。
2、有利于开发团队队员间在各个开发环节间确立沟通的标准,便于系统文档的制定和项 目的管理。因为UML的简单、直观和标准性,在一个团队中用UML来交流比用文字说明的文档要好得多。
3、UML为非专业编程人士理解软件的功能和构造,提供了一种直白、简单、通俗的方法。
4、使用uml可以方便理解各种框架的设计方式。
感受一下微信支付官方时序图:
在正式学习各种UML图的画法之前,先来感受一下APP集成微信支付的官网https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3的一个时序图,如下:
其整个交互的时序图为:
当然啦微信的这个支付集成流程有些复杂,但是通过来阅读这个时序图能让集成者对整个的流程有一个比较好的认识,所以UML图对于程序员而言是可以用最少的语言描述达到一个比较容易理解功能流程的非常直观有效的一种表达方式,所以在程序员的交流中如果有必要的话用一张清晰明了的流程图来表达要胜过千言。 在之后的UML学习中会要参考该时序图的。
面向对象模型(OOM)图【标红的则为重点图,需掌握】:
接下来直接开始复习各种UML图的画法,总共有12张,我们在PowerDesigner新建图时也能看到:
用例图(The Use Case Diagram)【重要】:
定义:
系统功能的视图。用例图(Use Case)是外部用户(被称为参考者)所能观察到的系统功能的模型图。用例图是系统的蓝图。用例图呈现了一些参考者,一些用例,以及它们之间的关系,主要是用于对系统、子系统或类的功能行为进行建模。
组成元素:
接下来咱们建立一下用例图实践一下:
然后对应的工具条上就有相关的元素:
这里以一个人去按摩店进行消费来进行一个用例描述,首先来列举一下该店里面提供的功能:
然后再画上参与者----人,分为大人和小孩:
接下来需要画上人之间的关系,很明显是一种继承关系,所以关系符用:
接下来参与者与用例之间得关联一下:
咱们先来画大人的:
当然此时的关联关系木有箭头,可以编辑改一下,这样好看一点:
此时再把其它的关联线也给改了:
好,再把小孩的用例关联上:
其中对于每一个用例其实都包含一个支付功能,所以包含关系就出来了:
此时就得用到工具栏的这个关系了:
然后再在包含关系的线上加上包含的字样,这样就比较明了,如下:
也可以使用英文:
最后将其完善:
而对于支付有多种支付方式,比如:
而它跟支付功能是一种扩展关系,而非包含关系,如下:
而它的画法需要注意一下方向:
其中包含与扩展这俩比较容易混淆,包含是必要条件,也就是我们要享受按磨服务时一定得要支付,而支付时并不是每一种都必须要有,只要其中的一个就成了,也就是支付方式就变为了一种非必要条件了,需要好好体会一下。
结构图:
它包含有四种图,其中最最重要的是类图,这个是必须要掌握的。
类图(The Class Diagram)【重要】:
定义:
是面向对象系统建模中最常用和最重要的图。主要是用来显示系统中的类、接口以及它们之 间的静态结构和关系的一种静态模型。是唯一可以直接映射到面向对象的语言。
作用:
1、分析和设计应用程序的静态视图。
2、描述一个系统的责任。
3、基地组件图和部署图。
4、正向和逆向工程。
正向工程是通过从特定实现语言的映射而把模型转换为代码的过程。
逆向工程是通过从特定实现语言的映射而把代码转换为模型的过程。
组成元素:
下面对其各种关系进行一个理论上的阐述:
- 泛化(Generalization):是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。例如:老虎是动物的一种,既有老虎的特性也有动物的共性。
- 实现(Realization):是一种类与接口的关系,表示类是接口所有特征和行为的实现。
- 关联(Association):是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子。关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
- 依赖(Dependency):是一种使用的关系,把一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖。
- 聚合(Aggregation):是整体与部分的关系,且部分可以离开整体而单独存在,如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。
- 组合(Composition):是整体与部分的关系,但部分不可以离开整体而单独存在,如公司和部门是整体与部分的关系,没有公司就不存在部门。
下面新建一张类图:
此时的工具栏上就多了一些按钮了:
下面还是以支付为例子来画一下类图:
先画一个下单接口:
双击对它进行一下编辑:
点击确定:
此时可以预览一下它生成的代码:
这就是所谓的正向工程,然后给这接口添加一些方法,如下:
预览一下代码:
确定:
既然有接口,那就肯定得有实现类,所以下面新建一下:
接下来则是需要画一下关系:
此时可以看一下代码预览:
有了这个代码预览功能就可以验证我们画的UML类图是否画得对,接下来在具体类中需要实现接口中的抽象方法,所以:
点击确定:
此时再看一下代码预览:
接下来再来新建一个下单管理类:
然后在里面添加一些方法:
其中这个有4个访问修饰符:
package:
private:
protected:
public:
咱们这还是定成private的,接下来再来定义方法,由于该管理类是一个单例对象,所以定义一个getInstance()方法:
并且该方法是静态的,所以:
此时再看一下代码预览:
点击确定:
接下来再定义一个下单方法:
接下来再创建一个网络管理类:
然后里面添加一个属性:
然后可以给它生成下构造方法:
再加两个网络类型判断方法:
好,接下来画一下关系,对于下单管理类肯定是要依赖于网络管理类的,所以:
而下单管理类跟下单接口实现类是关联关系:
此时看一下生成的代码:
/*********************************************************************** * Module: OrderManager.java * Author: xiongwei * Purpose: Defines the Class OrderManager ***********************************************************************/ import java.util.*; /** @pdOid c38fa9ae-97d1-4b62-989d-172e9277a938 */ public class OrderManager { /** @pdOid 2cb8adc1-665f-403e-a8e6-243d9446c01a */ private boolean isNetWork() { // TODO: implement return false; } /** @pdRoleInfo migr=no name=OrderAchieve assc=association1 coll=java.util.Collection impl=java.util.HashSet mult=0..* */ public java.util.Collection<OrderAchieve> orderAchieve; /** @pdOid befe4d63-177a-4866-a6d7-55e88a7acf98 */ public static OrderManager getInstance() { // TODO: implement return null; } /** @pdOid 0976ab18-6bfc-48e7-b598-57d0edd083c3 */ public void submit() { // TODO: implement } /** @pdGenerated default getter */ public java.util.Collection<OrderAchieve> getOrderAchieve() { if (orderAchieve == null) orderAchieve = new java.util.HashSet<OrderAchieve>(); return orderAchieve; } /** @pdGenerated default iterator getter */ public java.util.Iterator getIteratorOrderAchieve() { if (orderAchieve == null) orderAchieve = new java.util.HashSet<OrderAchieve>(); return orderAchieve.iterator(); } /** @pdGenerated default setter * @param newOrderAchieve */ public void setOrderAchieve(java.util.Collection<OrderAchieve> newOrderAchieve) { removeAllOrderAchieve(); for (java.util.Iterator iter = newOrderAchieve.iterator(); iter.hasNext();) addOrderAchieve((OrderAchieve)iter.next()); } /** @pdGenerated default add * @param newOrderAchieve */ public void addOrderAchieve(OrderAchieve newOrderAchieve) { if (newOrderAchieve == null) return; if (this.orderAchieve == null) this.orderAchieve = new java.util.HashSet<OrderAchieve>(); if (!this.orderAchieve.contains(newOrderAchieve)) this.orderAchieve.add(newOrderAchieve); } /** @pdGenerated default remove * @param oldOrderAchieve */ public void removeOrderAchieve(OrderAchieve oldOrderAchieve) { if (oldOrderAchieve == null) return; if (this.orderAchieve != null) if (this.orderAchieve.contains(oldOrderAchieve)) this.orderAchieve.remove(oldOrderAchieve); } /** @pdGenerated default removeAll */ public void removeAllOrderAchieve() { if (orderAchieve != null) orderAchieve.clear(); } }
其中就在里面是拥有一个下单接口的集合,然后还针对集合自动生成了一大堆的辅助方法。。当然咱们可以将其修改为1对1,则就没有这么多的集合相关的方法了,如下:
此时再看一下代码预览发生的变化:
然后再新建一个课程类:
里面定义点属性:
而它跟下单管理类是一种组合的关系,为啥,因为下单时离不开课程类,需要根据课堂的价格来进行下单,所以:
其中下单管理类的关系应该只有1个,所以改一下:
好,接下来再来回到下单管理类中的下单方法中增加一个参数,如何增加?
此时点击确认:
接下来再新建一个学员类,下单肯定是学员来触发的:
里面定义一下它的属性:
而学员又分为普通学员和VIP学员:
此时可以很方便的来继承父类的属性,如下:
同样的:
其中Vip学员是不需要下单的,只有普通学员需要下单变为Vip学员,所以普通学员和下单管理类则有一层关系:聚合
因为没有学员,其实也可以进行下单的,所以下单管理类可以离开学员而单独存在,所以画一下:
好,这个例子的关系已经画得差不多了,接下来,弄一个好玩的,将其正向工程生成Java代码:
这样通过类的关系模型就生成了我们想要的Java代码了,是不是很方便,不过目前生成的代码里面有大量没啥意义的注释,比如:
/*********************************************************************** * Module: NetWorkManager.java * Author: xiongwei * Purpose: Defines the Class NetWorkManager ***********************************************************************/ import java.util.*; /** @pdOid 96c6bb5b-31fa-4524-884f-5ca6de5e29be */ public class NetWorkManager { /** @pdOid 79cb90f0-5b97-4fd7-a9d3-33aa88e5792a */ public boolean isNetwork; /** @pdOid 38ad5e7b-a1c3-48e6-80bc-10ba86891eeb */ public NetWorkManager() { // TODO: implement } /** @pdOid 972b9a4f-5df1-42a2-838f-17f6aee2a896 */ public boolean isMobileNetwork() { // TODO: implement return false; } /** @pdOid 361bd5ab-9cc9-48bf-a17c-7bb0024ca889 */ public boolean isWifiNetwork() { // TODO: implement return false; } }
其实是可以去掉的,这里再重新生成一次:
点确定之后再来生成一次,则就干净了:
/*********************************************************************** * Module: NetWorkManager.java * Author: xiongwei * Purpose: Defines the Class NetWorkManager ***********************************************************************/ import java.util.*; public class NetWorkManager { public boolean isNetwork; public NetWorkManager() { // TODO: implement } public boolean isMobileNetwork() { // TODO: implement return false; } public boolean isWifiNetwork() { // TODO: implement return false; } }
以上是一个正向工程的过程,也就是将模型转换成代码的过程,而PowerDesigner还能逆向工程,也就是把代码转换成模型的过程,下面来试一下,咱们就将已经生成的Java代码逆成模型,先新建一个新的类图用来呆会逆向用:
然后再执行逆向菜单,如下:
点击确定就可以逆向成图啦。不过对于类图重点不是正向和逆向,而是要学会怎么来画类图。
组合结构图(Composite Structure Diagram):
定义:主要是用于描述类中的内部结构,和类与类之间的关系。它是比类图更加抽象的表示,一般来说先画组合结构图再画类图。注意事项:侧重类的整体特性,就使用类图;而如果侧重类的内部结构则使用组合结构图。
组成元素:
下面来实践一下,新建一张组合结构图:
然后下面还是以下单为例,先定义一个下单管理类:
可见对于组合结构图中的类来说就看不到具体细节了,接下来它里面会依赖于这几个东东,就得这样画了:
接下来再来画一个用户类,它里面的属性也可以当成它的一个部件,如下:
然后描述一下用户跟下单管理类的关系,可以用组合:
其关系的画法跟类图是一模一样的,只是围度不一样,这个图只关心类的一个结构。
对象图(Object Diagram):
定义:显示某一时刻对象和对象之间的关系,比如好理解,也就是描述对象的一些关系,而非类。
组成元素:
下面画一下:
然后还可以给该对象添加一些属性,如下:
再定义一下其它对象:
再来新建:
再表述一下它们的关系:
还有一个依赖关系,画一下:
包图(Package Diagram):
定义:顾名之意就是用来描述包与包之间的关系的。
组成元素:
下面新建一下简单使用一下,比较简单:
动态图【包含以下四种图】:
时序图(Sequence Diagram)【重要】:
定义:又名序列图、循序图、顺序图,是一种UML交互图。它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作。它可以表示用例的行为顺序,当执行一个用例行为时,其中的每条消息对应一个类操作或状态机中引起转换的触发事件。
组成元素:
如开篇我们看到的微信支付的时序图一样,下面咱们来画一下:
下面以用户下单为例子来简单的画一下:
接着开始下单:
在连线到下单之前得在这块增加一个控制焦点:
接着就会调用统一下单接口:
此时该接口会生成一个订单,则需要这样画了:
此时则会返回消息了,则需要用:
通信图(Communication Diagram):
定义:和时序图相同,只是表示形式不同,可直接转换。
组成元素:
下面咱们来将上面画的时序图直接转换成通信图来瞅瞅:
这样就将其转换成了通讯图了,不过默认生成的布局有些乱,得自己稍加排一下位置:
活动图(Activity Diagram)【重要】:
定义:表示一个过程,有点像流程图。这个在实际工作中是基本都会要用到的。
组成元素:
下面来画一个:
活动以圆点开始:
接下来有个条件分支:
另外为了可读,可以给这两条分支线上加入Y或N标识,如:
接下来在调起微信支付时又会有一个条件分支:
而对于查询服务器也存在成功与失败的分支,如下:
当支付成功之后,则整个流程也就结束了,所以画一个结束符:
以上是一个异步的流程图,下面再来看一下同步的流程图得如何来画?
接下来就得画同步处理了,需要用到它:
状态图(Statechart Diagram):
定义:表示过程中的状态情况。
组成元素:
这里就不画了,直接看一下例子就秒懂了:
交互纵横图(Interaction Overview Diagram):
定义:用来表示多张图之间的关联
组成元素:
基本都没听说过,下面来用一下:
然后它只能关联时序图和通信图,所以先来添加到我们的这张图上,点击:
点击到图上时,就会立马弹出一个框让我们选择相关的图,这里先选一下之前画过的时序图
再添加一张通讯图,这样才能表达两者的关系:
了解一下既可,基本上实际不会用它。
交互图:
组件图(Component Diagram):
定义:主要目的是显示系统组件间的结构关系。
组成元素:
比较简单,大致看一下示例了解既可:
部署图(Deployment Diagram):
定义:多数用于表示硬件结构,做系统集成很方便。
组成元素:
看一下示例:
可能搞运维的会有画这种图的需求,下面还是稍加演练一下,新建一张部署图:
先画几个结点:
然后再搞一个部件:
其中每一个元素都可以换一张直观的漂亮图,比如说:
艾玛~~以上就完整的将整个UML的各种图的画法过了一遍,真是不容易,以后UML就不想再学了,仅此这篇作为以后的备忘。。