作者:mingjava 文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=858
本文内容摘自即将出版的《Symbian OS J2ME编程指南》一书,关于本书的详细介绍请访问:http://www.china-pub.com/computers/common/info.asp?id=25538
6.1 概述
在本章和下一章,我们将讨论如何使应用程序尽可能地可移植,以及如何编写高效的代码。尽管Java(尤其是无线Java)并非“编写一次,到处运行”,将Java MIDlet移植到不同的无线设备上通常还是比较简单的。和移植相关的问题源于手机的多样性:不同的堆内存、不同的持久化存储、不同的屏幕尺寸,以及不同的用户输入方式都使得一个应用程序在一系列设备上以一致的行为运行的难度大大增加。一些设备还有可选的API包,还要为每一个操作考虑到网络问题,如允许的JAR文件尺寸。
这一章将研究如何开发能在尽可能多的手机上移植的MIDlet。我们将讨论如何使用设计模式和代码编写准则来帮助移植,使开发者能从自己的努力中获得最大的可重用性。
创建可移植代码的价值被市场上一系列Java设备扩大化了。它们中的许多都是相似的;例如,Series 60平台为一系列设备提供了一个创建应用程序的方式。甚至在Series 60设备中,开发环境也是有不同的。一些手机包括Wireless Messaging API(JSR 120)和Java蓝牙API(JSR 82)。新出的Series 60设备,如Nokia 6600,支持MIDP 2.0,早期的设备如Nokia 3650,仅支持MIDP 1.0。Symbian系统设备也有不同的用户界面。它们不同大小的屏幕,更显著的是用户输入方式的不同:Sony Ericsson P900使用一个非常大的触摸屏和一个小的操纵杆,而通常Series 60手机都有较小的屏幕并使用键盘和一个方向操纵杆。
然而,这些不同点并不意味着:一个应用程序不得不完全重写以便运行在所有的设备上。不管我们的应用程序使用等Form、TextField和List高级组件,还是使用Canvas自己绘制和处理事件(或者同时使用这些技术),我们仍然能够做许多工作使得我们的MIDlet可移植。
最后,核心应用程序应当在不同设备上均保持不变,任何不同都应该是由于不同的用户界面引起。例如,图形操作可能由于较小的屏幕而改变,或者根据不同的用户输入而创建不同的菜单。确保核心应用程序保持不变需要将其从UI中分离,这需要基于一个恰当的模式。
开发者除了要创建一个可移植的架构,还要满足不同设备的性能。这需要知道设备支持哪些API并相应更改MIDlet。
当讨论编程模型时,我们还将讨论Symbian系统设备的不同之处,并看到这将影响到应用程序的实现。
6.2 设计模式
已经有许多类型的结构设计可以在面向对象的编程语言如Java中采用,这有助于代码的可移植性。虽然我们不打算讨论设计理论的细节,通常在MIDlet开发中考虑重要的概念还是值得的。传统上,这些设计都是与桌面应用程序或基于服务器的应用程序开发关联的;然而,由于内存和处理器能力的约束对无线应用程序越来越小,这些模式变得愈加重要。下面的章节将介绍两种有用的设计模式。
6.2.1 模型-视图-控制器设计模式
这是在GUI应用程序中广泛使用的模式。它将应用程序分为3个特定的实体:一个模型、一个视图和一个控制器。每个实体都依赖于其他实体,但是自身拥有特定的功能。模型-视图-控制器(Model-View-Controller,MVC)模式可以追溯到Smalltalk编程语言的UI模型。这3种实体如下:
· 模型(Model):也叫做(也许更为恰当)引擎(Engine)。模型持有应用程序的数据。它处理来自控制器的请求并改变数据。它和视图关联,当其数据改变后,通知视图更新显示,这样确保数据的最新状态反映到视图上。它还响应来自视图的查询模型状态的请求。简言之,它提供了应用程序的核心业务逻辑。
· 视图(View)。模型视图负责将数据表现给用户。为了响应来自模型的通知,视图获得数据的当前状态并绘画它到屏幕。它还提供接受用户输入的用户界面。
· 控制器(Controller)。控制器负责管理应用程序的流程。它响应捕获自视图的用户输入,处理输入并向模型发送指令来相应地改变其数据状态。
一个基本的MVC实现的UML类图如图6.1所示。这些对象间的交互在UML序列图(见图6.2)中可见。
图6.1 MVC模式的一个简单示例
6.1 MVC模式的一个简单示例
图6.1 MVC模式的一个简单示例
图6.2 MVC模式中对象的交互
MVC模式中的一个思想便是使应用程序的组件之间实现松耦合。它允许数据的表示(视图)从引擎和其数据(模型)中分离。它还允许(同时刷新的)多视图共用一个模型(例如,相同的数据可能被同时表示为一个表格和一个饼图)。实际上,MVC模式的实现要比图6.1所示的简化示例复杂得多,包括多实例的视图类(所有的视图都派生自一个抽象的视图类),可能每个视图都与一个控制器(派生自一个抽象的控制器)关联。
6.2.2 模型-视图设计模式
模型-视图模式(MV)是MVC模式的一个简化版本。MV模式是观察者(Observer)模式(也叫做发布者-订阅者)的一个变形。在MV模式中,视图类组合了MVC模式中视图和控制器的功能。在MV类图中,视图类对于桌面Java GUI开发者来说非常熟悉(甚至他们自己都不曾意识到),因为典型的应用程序UI就使用了它。例如,如下所示的UI类本质上就是MV模式中一个视图类:
public class MyCanvas implements MouseListener, KeyListener {
public MyCanvas() {
...
addMouseListener(this);
addKeyListener(this);
}
...
}
在MV模式下,应用程序的类可以分为以下两组组件:
· 模型(Model)。模型管理应用程序的数据。它根据其现有状态响应来自视图的查询,当视图请求时更新模型的状态。当数据状态改变后,它将通知视图。
· 视图(View)。视图表现模型的数据。它响应用户输入,指示模型相应地更新其数据。在得到模式数据改变的通知后,它获得新的模型状态并绘画最新的数据状态。
这个简化的模型也许更适用于简单的MIDlet应用程序。它没有过度复杂化类的结构,应用程序软件可以明显地分为两个组:一个负责UI,其他负责应用程序的核心逻辑。这还意味着,移植应用程序到不同的MIDP设备可能会使用完全不同的UI界面(例如,从一个基于触摸屏的Sony Ericsson P900到一个基于键盘的Nokia 6600),但不必涉及到模型类的更改。
假定一个基于MV的应用程序支持一个基于手写笔(pointer)的视图和一个基于键盘的视图,其UML类图如图6.3所示。
图6.3 模型-视图设计模式对多视图的支持
6.3 模型-视图设计模式对多视图的支持
图6.3 模型-视图设计模式对多视图的支持
6.2.3 设计模式的实际应用
事实上,在无线Java开发中,这些设计技巧应当谨慎地使用。一些诸如整个应用程序尺寸的限制可能会约束这些实现。即使是最小的类也会使整个应用程序尺寸增大200字节,这将最终导致更大的JAR文件;可能需要减少类的抽象层次来保持JAR文件在一个合理的大小范围内。然而,理论和方法仍然是有效的,并且无线设备受到资源的限制也将越来越小。
基于MIDP 2.0的Symbian系统的设备大概有两种用户界面。像Series 60的Nokia 6600之类的手机提供了一个键盘接口,而基于UIQ的Sony Ericsson P900提供了一个触摸笔的UI界面。此外,这两种手机还有不同的屏幕尺寸:Series 60手机分辨率为176×208像素,UIQ手机分辨率为208×253像素。因此,一个应用程序从一种设备移植到另一种设备可能需要更改应用程序代码。如果使用高层API,开发者可以让MIDP底层实现来自己负责UI。然而,如果开发者进入动作游戏领域,就完全不同了。
游戏应用程序通常需要使用低级API,因为它给予开发者像素级的控制。诸如Sprite和Layer之类的对象使开发者能够创建动画来向用户表现虚拟世界。然而,底层的图像文件需要针对屏幕尺寸和性能来优化。还可能需要其他的改变。例如,一个基于层的游戏移植到另一个拥有较小屏幕的设备上时,可能就需要较小的层并减少复杂度。
游戏开发的另一个问题是捕获用户输入。基于UIQ的P900这样的触摸屏设备,与那些使用键盘的设备有不同的处理方式。由于捕获输入的方式不同(例如,在Canvas类中,使用pointerPressed而不是keyPressed),就可能需要以不同的方式处理用户输入以确保游戏仍然能正确运行。用设计模式的术语来说,这可能需要一个抽象的层,如MVC模式中的控制器(Controller),来扮演UI(视图)和应用程序游戏逻辑(模型)之间的中介,以确保正确处理用户输入而不管UI是什么类型的。无论如何设计,将用户界面从应用程序的核心逻辑中独立出来是非常重要的,它允许游戏逻辑在不同平台和UI间保持不变。
这将使得负责创建用户界面的开发小组能更集中精力为一个新设备创建UI而不必理解游戏底层的逻辑。他们能考虑更多的Sprite图像并对用户交互类做出更改,却不必触及游戏的核心类。分离UI可以通过抽象的核心类更容易地实现(例如,在MVC设计模式中,使用抽象的View类和抽象的Controller类)。这就为应用程序的其他模型类提供了一系列标准接口。派生的类负责具体实现;例如,每个ConcreteView类可能对应一个ConcreteController(见图6.4)。
图6.4 使用抽象将UI从引擎中独立出来
这些方法创建了一系列可复用的组件,它们可以在许多设备上实现而避免大规模地重写应用程序。
6.2.4 小结
在这一节中,我们看到了如何使用已有的设计模式为架构来设计应用程序。这些模式已被广泛地使用在服务器和桌面应用程序中;然而,这些准则依然在无线世界中有效,尽管一些角色需要被压缩以适应受限的设备本地环境。当我们确信不需要为JAR文件的大小担心时,我们就应当使MIDlet尽可能的可移植。