应用MVC设计模式解决J2ME应用程序导航问题

开发MIDlet的程序员也许经常会被界面的导航问题所困扰,尤其界面比较多的时候,通常有七、八个界面就会很让人头疼了。本文讲述如何应用MVC设计模式解决这类的问题。

MVC设计模式已经非常的成熟并在WEBApplication的开发中广泛使用,apache的开源项目struts就是典型的例子。MVC的本质就是是逻辑和显示分开,通过控制器进行协调。通常我们会感到控制器比较的肥大,这个是个有争议的问题。MIDP的用户界面开发是比较简单的,只有那么20几个类。但是由于导航一般只能通过Command来实现,所以界面增多的情况下,如果没有有效的组织那么程序写起来非常的乱,最致命的是这样的程序可读性差、扩展性差、可维护性差。

应用MVC解决这个问题的关键是提供一个桥梁作用的控制器,它通常要有一个MIDlet作为参数。例如publicUIController(PhoneBookMIDletpbm)

{

this.phoneBookMIDlet=pbm;

}

为了传递事件,你可以定义一个内部类,在里面定义事件的代号。这样用起来非常的方便例如

publicstaticclassEventID

{

privateEventID()

{

}

publicstaticfinalbyteEVENT_NEW_RECORD_SELECTED=1;

publicstaticfinalbyteEVENT_SAVE_RECORD=2;

publicstaticfinalbyteEVENT_NEWPHONE_BACK_MAINUI=3;

publicstaticfinalbyteEVENT_LISTPHONE_BACK_MAINUI=4;

publicstaticfinalbyteEVENT_SEARCHUI_BACK_MAINNUI=5;

publicstaticfinalbyteADD_NEW_RECORD=100;

publicstaticfinalbyteSEARCH_RECORD=101;

publicstaticfinalbyteCLEAR_RECORD=102;

publicstaticfinalbyteLIST_RECORD=103;

publicstaticfinalbyteHELP=104;

}我们要在这个控制器内初始化各个界面类,这样我们才能根据不同的事件代号进行导航。

publicvoidinit(Modelmodel)

{

this.display=Display.getDisplay(phoneBookMIDlet);

this.model=model;

indexFunctionUI=newIndexFunctionUI(this);

infomationUI=newInfomationUI();

newPhoneUI=newNewPhoneUI(this);

listPhoneUI=newListPhoneUI(this);

searchPhoneUI=newSearchPhoneUI(this);

displayWelcome();

}

publicvoidsetCurrent(Displayabledisp)

{

display.setCurrent(disp);

}

publicvoidsetCurrent(Alertalert,Displayabledisp)

{

display.setCurrent(alert,disp);

}由于本文主要讲述如何实现导航,因此关于Model不做任何介绍。细心的话你也许可以看出来我这些代码是在完成一个电话簿的功能。在从RecordManagementSystem从入门到精通之四中我会介绍自己编写的电话本。在控制器类中最重要的就是接受事件然后进行导航,也就是显示不通的界面。因此它的事件处理的方法是这样的。

publicvoidhandleEvent(inteventID)

{

switch(eventID)

{

caseEventID.ADD_NEW_RECORD:

{

display.setCurrent(newPhoneUI);

break;

}

caseEventID.LIST_RECORD:

{

display.setCurrent(listPhoneUI);

break;

}

caseEventID.SEARCH_RECORD:

{

display.setCurrent(searchPhoneUI);

break;

}

caseEventID.EVENT_NEWPHONE_BACK_MAINUI:

{

display.setCurrent(indexFunctionUI);

break;

}

caseEventID.EVENT_LISTPHONE_BACK_MAINUI:

{

display.setCurrent(indexFunctionUI);

break;

}

caseEventID.EVENT_SEARCHUI_BACK_MAINNUI:

{

display.setCurrent(indexFunctionUI);

break;

}

default:

break;

}

}

publicvoidhandleEvent(inteventID,Object[]obj)

{

}这是个重载的方法,当有参数传递过来的时候我们调用后面的方法。

接下来我们看界面类,它们通常包括控制器类、界面的Item还有一些Command。

publicNewPhoneUI(UIControlleruicontroller)

{

super(Title.add_record);

this.uicontroller=uicontroller;

nameField=newTextField(Title.name,null,25,TextField.ANY);

mobileField=newTextField(Title.mobile,null,25,

TextField.PHONENUMBER);

choice=newChoiceGroup(Title.choice,ChoiceGroup.MULTIPLE);

phoneField=newTextField(Title.phone,null,25,TextField.PHONENUMBER);

emailField=newTextField(Title.email,null,25,TextField.EMAILADDR);

choice.append(Title.detail,null);

this.append(nameField);

this.append(mobileField);

this.append(choice);

this.addCommand(saveCommand);

this.addCommand(backCommand);

this.setCommandListener(this);

this.setItemStateListener(this);

}通常他们把控制器类作为参数传递给构造器,并在构造器内部注册监听器,绘制界面等。它们通过commandAction()方法来传递事件编号给控制器类去处理,例如

publicvoidcommandAction(Commandarg0,Displayablearg1)

{

//TODOAuto-generatedmethodstub

if(arg0==backCommand)

{

uicontroller

.handleEvent(UIController.EventID.EVENT_NEWPHONE_BACK_MAINUI);

}

}这样就基本上完成了导航问题,扩展起来非常容易,添加一个界面类,然后在控制器类中初始化并添加适当的事件编号就可以了。

想起来,这种解决方法真是非常经典!!

相关推荐