1、转】UML建模与Android应用程式开发(上) 前言 就一个完整的软体系统而言,程式码只是系统(本体)的一个观点(View)而已,而模型(Model)也是系统(本体)的一个观点。当Android应用开发者来说,若既能从程式码看应用系统,又能从模型看它,就相当于人们都有两只眼睛来看前方的一切事物。一旦发现两者有不一致的情形,就表示两者可能有所失真(即远离本体)了。这样的讯息,可让开发者提前知道未来开发路子上,可能发生的错误,以便防患未然。同样地,在模型大观点里,也含有许多小观点,例如: l 架构观点:一般采用UML 类别图(Class Diagram) l 使用观点:一般采用
2、UML 用例图(Use Case Diagram) l 顺序观点:一般采用UML 顺序图(Sequence Diagram) l 状态观点:一般采用UML 状态图(Statechart Diagram) 在本文里,将说明如何就上述的4个小观点,来构成模型大观点,然后再与程式码观点汇合,成为一个稳定可靠、简洁高雅的Android应用系统。然而,特别留意的是:模型观点与程式码观点两者不一定要有明确的先后顺序关系。两者之间,到底何者先,而何者后,并非重点。因为最好的状态是:在脑海里先两者并存,先领悟构思,然后才画出UML模型图,也写出程式码,但都不一定是完美的。随着两个观
3、点的对比,发现不一致现象,就像两只眼睛发现前方物体的呈像不一致时,两者自然而然会逐渐修正(Iterative & Incremental),止于至善。 本文范例 本文举一个简单范例:一个Activity的子类别,以及一个远程的(Remote)的Service 子类别。两者透过 Android的IPC机制相互沟通。 多种UML 类别图呈现各种架构观点 所有的模型图都是人们对某项事物本体认知的心智观点,随着观点和抽象的角度之不同而改变其所呈现之面貌。例如,当我们觉得Android框架里的基类(即抽象类)是最重要的,只要呈现它即可,此时类别图就呈现如下:
4、 图1 独尊Android框架的类别图 如果觉得应用子类别也是架构里的重要元素,需要与框架里的基类别一起呈现出来,则此时类别图就呈现如下: 图2 兼具框架与应用的类别图 当然也有许多人习惯于独尊应用子类别,而认为不需要呈现幕后的框架基类别,则此时类别图就呈现如下: 图3 独尊应用子类别的类别图 此外,还有人习惯于独尊介面(即接口),而对幕后实作类别视而不见,则此时类别图就呈现如下: 图4 强调介面(即接口)的类别图 以上都只强调架构里的元素(如
5、类别和介面),还有人认为这些元素之间的互动(Interaction)与合作(Collaboration)是非常重要的,需要表现出来,此时类别图就呈现如下: 图5 强调互动的类别图 UML 用例图呈现使用观点 类别图是基于架构师的观点,偏向系统的内观(Internal View)。至于用例图(Use Case Diagram)则是基于使用者(即用户)的观点,偏向系统的外观(External View)。许多人坚持需求至上(Requirement-based)的开发者,非常重视这项UML图,终究用户是买家,就行销的角度来看,用户观点当然非常重要啰。例如,针对
6、上述范例的UML用例图呈现如下: 图6 强调用户观点的UML用例图 UML 顺序图呈现各项活动发生顺序 如何去实现上述的用例呢? 为了实现上述的用例,系统必须执行一连串的活动(Action)。有人认为这些用例幕后的活动执行顺序是很重要的,就使用UML顺序图来表达之,例如,针对用例「Run」可绘制其幕后活动的执行顺序,如下述的UML顺序图: Use Case: Run 图7 Run用例幕后的活动顺序图 再如,针对用例「Exit」可绘制其幕后活动的执行顺序,如下述的UML顺序图: Use Case: E
7、xit 图8 Exit用例幕后的活动顺序图 UML 状态图呈现UI 画面的千变万化 由于Android是属于事件驱动(Event-Driven)的平台系统,有许多人主张善用UML状态图可对众多事件分而治之,于是在清晰的状态之下,会执行明确的活动。例如,下述的画面可接受来自Android和用户所引发的事件。 此时,可以采用UML状态图呈现UI变化之观点,如下图: 图 9 呈现UI画面状态变化的UML状态图 以Java 语言表达程式码的观点 至今天,还是有许多人维持传统的观点: l 画UML
8、模型图在先,撰写程式码在后。 l 程式码是UML模型的实践。 l UML模型较为抽象,程式码较为具体。 这项传统观点并没有对与错。但是,近年来,愈来愈多的人们持着新的观点: l UML模型图与Java程式码是两个同位阶的观点。 l 两个观点的一致性是确保系统稳定可靠、简洁高雅的重要途径。 l 杰出的Android开发者应该兼具两个观点。 经过两个观点的互相核对与逐步修正后,的确呈现出极为完美的程式码,如下: Android应用程式Project 这包含了1个IA.java介面定义档,及两个应用子类定义档: 应用程式码 一致化的程式码如下所
9、示: // IA.java接口 package com.misoo.pk01; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; public interface IA { int f1(int x)throws RemoteException; public static abstract class Stub extends Binder implem
10、ents IA { @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException { int x = data.readInt(); int y = this.f1(x); r
11、eply.writeInt(y); return true; } public abstract int f1(int x) throws RemoteException; public static IA asInterface(IBinder obj){ return new Proxy(obj); } //-------------------------------------------
12、 private static class Proxy implements IA{ private IBinder mRemote; public Proxy(IBinder ibinder) { mRemote = ibinder; } public int f1(int x) throws RemoteException { // TODO Auto-gene
13、rated method stub Parcel data = Parcel.obtain(); data.writeInt(x); Parcel reply = Parcel.obtain(); mRemote.transact(0, data, reply, 0); return reply.readInt(); } } } }
14、 // myService.java package com.misoo.pk01; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class myService extends Service { @Override public IBinder onBind(Intent intent) {
15、 return mBinder; } public int mySf1(int x){ return x + 1000; } //--------------------------------------------- private final IA.Stub mBinder = new IA.Stub() { @Override public int f1(int
16、x) throws RemoteException { return mySf1(x); } }; } // myActivity.java package com.misoo.pk01; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android
17、content.ServiceConnection; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public cla
18、ss myActivity extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private Button btn, btn2; private TextView tv; private IA ia;
19、 private int state_var_A = 0; public void onCreate(Bundle icicle) { super.onCreate(icicle); if(state_var_A == 0){ show_layout_01(); goto_state_01(); } } private vo
20、id show_layout_01(){ LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new Button(this); btn.setBackgroundResource(R.drawable.heart); btn.setId(101);
21、 btn.setText("Run"); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 55); param.topMargin = 10; layout.addView(btn, param); btn2 = new Button
22、this); btn2.setBackgroundResource(R.drawable.heart); btn2.setId(102); btn2.setText("Exit"); btn2.setOnClickListener(this); layout.addView(btn2, param); tv = new TextView(this);
23、tv.setTextColor(Color.WHITE); tv.setText(""); LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout); }
24、private void goto_state_01(){ state_var_A = 1; bindService(new Intent("com.misoo.pk01.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName cla
25、ssName, IBinder ibinder) { ia = IA.Stub.asInterface(ibinder); } public void onServiceDisconnected(ComponentName className) { } }; public void onClick(View v) { int ret=0; switch(v.getId()){ ca
26、se 101: if(state_var_A == 1){ try { ret = ia.f1(188); } catch (Exception e) { e.printStackTrace(); }
27、 tv.setText(String.valueOf(ret)); } break; case 102: if(state_var_A == 1) { stopService(new Intent("com.misoo.pk01.REMOTE_SERVICE"));
28、 finish(); } break; } } } 结语 在传统观点里,大多先绘制UML模型图,然后才开始构思程式码的撰写,使得UML建模成为撰写程式码的前置工作,因此许多程式员将UML建模视为多余的负担。为了节省开发成本,就将省略掉UML建模的工作了。 在新潮的观点里,UML模型与程式码是软体系统本体的两个观点(或面向),两者没有先后顺序关系,而是并存和兼具于同一个人的脑海里。这就像两只眼睛看到的景象并存于一个人的脑海里一般,如此才能看到更真实的世界,也能做出更完美的软体系统来。从本文的范例,你可看到当UML模型与程式码两个观点一致时,真的能让软体系统既可靠又高雅,不亦美哉! 另一篇文章:
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4009-655-100 投诉/维权电话:18658249818