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