Symbian OS:MVC 设计模式在 SymbianOS 应用程序中的应用分析

来源:互联网 发布:大连理工大学软件学院 编辑:程序博客网 时间:2024/06/05 06:54
简介  
       MVC设计模式是在20世纪80年代发明的一种软件设计模式,至今已被广泛使用,后来被推荐为 Sun 公司 J2EE 平台的设计模式。 
 
  随着Web应用的商业逻辑包含逐渐复杂的公式分析计算、决策支持等,使客户机越 来越不堪重负,因此将系统的商业分离出来。单独形成一部分,这样三层结构产生了。 其中‘层’是逻辑上的划分。[1-3]
 
体系结构  表现层(Presentation layer):包含表示 
   
mvc模式的体系结构
[5]
代码、用户交互GUI、数据验证。 该层用于向客户端用户提供GUI交互,它允许用户在显示系统中输入和编辑数据,同时 系统提供数据验证功能。 
 
  业务逻辑层(Business layer):包含业务规则处理代码,即程序中与业务 相关专业算法、业务政策等等。该层用于执行业务流程和制订数据的业务规则。业务逻 辑层主要面向业务应用,为表示层提供业务服务。 
 
  数据持久层(Persistence layer):包含数据处理代码和数据存储代码。数据持久层主要包括数据存取服务,负责与数据库管理系统(如数据库)之间的通信。 三个层次的每一层在处理程序上有各自明确的任务,在功能实现上有清晰的区分, 各层与其余层分离,但各层之间存有通信接口。 [3] 
 
编辑本段模式结构
  视图:数据的展现。 
 
  视图是用户看到并与之交互的界面。视图向用户 
  MVC设计模式中的三个模式结构 
MVC设计模式中的三个模式结构
[6]
显示相关的数据,并能接收用户的输入数据,但是它并不进行任何实际的业务处理。视图可以向模型查询业务状态,但不能改变模型。视图还能接受模型发出的数据更新事件,从而对用户界面进行同步更新。 
 
  模型:应用对象。 
 
  模型是应用程序的主体部分。 模型代表了业务数据和业务逻辑; 当数据发生改变时,它要负责通知视图部分;一个模型能为多个视图提供数据。由于同一个模型可以被多个视图重用,所以提高了应用的可重用性。 
 
  控制器:逻辑处理、控制实体数据在视图上展示、调用模型处理业务请求。 
 
  当 Web 用户单击 Web 页面中的提交按钮来发送 HTML 表单时,控制器接收请求并调用相应的模型组件去处理请求,然后调用相应的视图来显示模型返回的数据。[2-3] 
 
编辑本段优点
  采用三层软件设计架构后,软件系统在可扩展性和可复用性方面得到极大提高,在资源分配策略设计合理运用的同时,软件的性能指标得到提升,系统的安全性也得到改善。 
 
  三层体系结构对Web应用的软件架构产生很大影响,促进基于组件的设计思想, 产生了许多开发Web层次框架的实现技术。较之两级结构来说,三层结构修改和维护上 更加方便。目前开发B/S结构的Web应用系统广泛采用这种三层体系结构。 [3] 
 
编辑本段运行机制
  在 MVC 模式中,Web 用户向服务器提交的所有请求都由控制器接管。接受到请求之后,控制器负责决定应该调用哪个模型来进行处理;然后模型根据用户请求进行相应的业务逻辑处理,并返回数据;最后控制器调用相应的视图来格式化模型返回的数据,并通过视图呈现给用户。[3][7]
 
1.MVC模式概述
  MVC 模式包括三个部分:模型(Model)、视图(VIEW)和控制器(CONTROLLER),分别对应于内部数据、数据表示、输入输出控制部分。模型
是软件独立于外部表现的内在抽象,是包含了核心数据和逻辑功能计算的应用,它独立于界面的表达。视图View是模型的外在表现。它从模型中获得
信息,并在屏幕上加以显示。控制器Controller定义用户界面对用户输入的响应,它的职责是对模型中任何变化的传播加以控制。确保用户界面和模型
之间的对应关系,协调着模型和视图的工作。模型和视图的分离使得一个模型可以对应多个视图。模型、视图和控制器之间的关系如下图所示。用户输入表示
用户和用户界面之间的相互交互关系,通过控制器,把用户输入与用户界面连接起来。视图通过控制器来响应用户输入。视图和模型之间是相互协作的关系。
即一个是同得到用户的输入,以此来改变模型状态。同时,模型又将自己的改变状态通知给它的所有视图,而视图在得知这些变化之后,自己做相应
的改变,将视图的改变及时展现给不同的用户。这样做的好处是将用户输入、用户界面的显示和模型分离开来,减小了他们之间的耦合度。MVC将模型
与视图的分离,不仅提高了系统的灵活性和复用性,而且为用户软件界面的提议接哦故的研究奠定了基础。
 

MVC,model-view-control,这是一个架构模式,也是一种开发模式。

不论设计模式还是架构模式,MVC都是最经典的模式。

Symbian OS作为最热的手机开发平台之一,Symbian OS是一个微内核的系统,它应用了大量的模式进行高度模块化设计,

便于根据需求的变更和新环境进行扩展和改善适应。MVC便是其中一个模式。

回顾一下MVC的含义吧,

MVC设计模式它提供一种能够分别修改软件的不同模块的能力,提高软件的健壮性和复用性。

MVC模式能够帮助软件的设计者使用面向对象的设计原则,比如:开闭原则,通过继承而不是修改存在的基类,增加新的代码和类来扩展设计。Model:包含和操作程序中的数据,它最重要的部分是应用程序的数据结构View:定义数据模型向用户显示的方式;View传递接收到的命令和请求给controller,View是图形接口,它从Model读,并且获取需要显示的数据给用户Controller:定义用户接口对收到的命令和请求的处理,操作Model中的数据并更新View

MVC可以使得开发者根据面向对象编程的基本原则来设计他们的应用程序,开发者在实现之前必须决定应用程序的那些部分是可以扩展的哪些是不行的。设计阶段之后,代码的开发从一些基类开始,可以通过增加新的特别的类来扩展。MVC和OCP是一致的。

在Symbian S60中,MVC的使用是基于Avkon的GUI框架,框架提供基类实现Model,View和Controller。

这些类可以被应用程序设计者扩展。Avkon的基类:-CAknApplication,应用程序的基类-CAknDocument,Modle的基类-CAknAppUI,Controller的基类View的父类AVkon没有提供,但是可以从CONE环境继承。

应用程序架构(Application Framework)

 

1、S60应用程序架构

    S60平台在底层Uikon应用程序框架上添加了一个用户界面层(Avkon)。Avkon提供了一套特别为S60设计的UI组件和应用程序框架。

 

1.1、S60应用程序结构

 

1.1.1、模型(Model)—视图(View)—控制器(Controller)模式(MVC)

Symbian <wbr>OS <wbr>鈥 <wbr>应用程序架构

    MVC模式在S60 UI应用程序中是一个通用的设计模式。应用程序被分离成不同的逻辑部分;它们包装了应用程序的不同方面。每个部分都用特殊的任务。MVC模式分离了应用程序设计,使模型(Model)的代码得到重用。

    模型(Model):

  • 封装了应用程序的状态和功能。
  • 通知视图(View)进行切换。
  • 响应来自视图(View)的状态查询。

    视图(View):

  • 呈现模型(View)。
  • 接收来自模型(Model)的视图更新通知。
  • 将用户的输入发送给控制器(Controller)。

    控制器(Controller):

  • 定义了应用程序的行为。
  • 将用户操作与模型(Model)更新相映射。
  • 响应视图(View)切换请求。

1.1.2、S60应用程序结构和MVC

    S60应用程序通常分离成两大部分,引擎(Engine)和UI。应用程序引擎,也就是应用程序模型,用来处理逻辑运算和数据结构表示。应用程序UI,用来在屏幕上显示应用程序的数据和全部的行为。在基于S60应用程序框架下,实现引擎和UI分离模式有三种方式:传统的Symbian OS应用程序构架、对话框构架、视图切换构架。不同的构架只反映UI的实现,应用程序类(CAknApplication继承类)和文档类(CAknDocument)并没有区别。

Symbian <wbr>OS <wbr>鈥 <wbr>应用程序架构

应用程序UI的组成:

    CAknApplication继承类:

  •     应用程序框架的启动对象。
  •     定义了应用程序的性质。
  •     创建文档(CAknDocument)类。

    CAknDocument继承类:

  •     创建AppUi(Controller)。
  •     提供了应用程序数据的持久化功能。

    CAknAppUi或CAknViewAppUi继承类(Controller):

  •     基类的选择依赖于应用程序架构。
  •     处理应用程序事件。
  •     控制应用程序模型(Model)。
  •     负责切换视图(View)。

    CCoeControl继承类(View):

  •     显示模型(Model)状态。
  •     接收用户输入。
  •     向控制器通知相关事件。
  •     根据模型(Model)变化更新显示。

应用程序引擎(Engine):

  •     封装了应用程序数据和状态。
  •     封装了非UI依赖的功能,能够在其他UI平台重用。
  •     通常以类库的形式实现。
  •    AppUi直接操作。

1.2、传统的Symbian OS 应用程序架构

 

1.3、对话框(Dialog)架构

 

1.4、视图切换架构

    视图切换架构是一种机制,它允许应用程序注册视图,并且在任意时刻只有一个视图被激活。视图切换架构并没有规定视图的具体内容,而是为视图在屏幕上显示提供了支持。

Symbian <wbr>OS <wbr>鈥 <wbr>应用程序架构

    与传统的Symbian OS应用程序架构不同的是,AppUi类(Controller)继承自CAknViewAppUi,并且引入了一个新类CAknView作为AppUi(Controller)和容器(Control)之间的媒介。在视图切换架构中,CAknView派生类称为Avkon视图(View),它拥有一个容器。AppUi创建每个Avkon视图并且在服务器端进行注册。切换视图时使用视图UID进行切换。

 

1.4.1、创建视图

    CAknView派生类实例的创建通常在AppUi对象的ConstructL()方法中进行。该方法中将所有的视图进行注册,并设置一个默认视图:

    void CMyViewArchAppUi::ConstructL()

    {

        BaseConstructL();

        CMyViewArchAppView1* view1 = new(ELeave) CMyViewArchAppView1;

        CleanupStack::PushL(view1);

        view1->ConstructL();

        AddViewL(view1); // Transfer ownership to CAknAppUi.

        CleanupStack::Pop();  // pop view1.

        CMyViewArchAppView2* view2 = new(ELeave) CMyViewArchAppView2;

        CleanupStack::PushL(view2);

        view2->ConstructL();

        AddViewL(view2); // Transfer ownership to CAknAppUi.

        CleanupStack::Pop();  // pop view2.

        SetDefaultViewL(*view1);

        // More code

    }

    另外,视图本身并不具有绘制控件的能力,所以每个视图需要包含派生自CCoeControlMCoeControlObserver的控件容器:

    class CMyViewArchAppView1Container : public CCoeControl, MCoeControlObserver

 

1.4.2、Avkon视图类

    每个Avkon视图类就像一个小型的AppUi。它必须提供一个Id()函数,从而系统可以标识这个视图,并且必须实现DoActivateL()和DoDeactivate()函数来完成视图激活和注销时的具体操作,此外还应该实现HandleForegroundEventL()、HandleCommandL()和HandleStatusPaneSizeChange()函数用于处理各种事件。

    DoActivateL()

    当视图被激活时,将调用该函数。该函数负责实例化并显示视图的控件。在视图被注销前可能多次调用该函数,所以实现该函数必须考虑重复实例化控件。

    DoDeactivate()

    当视图被注销时,将调用该函数,负责销毁视图中的控件。只有当应用程序退出时,或者激活同一个程序的另一个视图时,激活的视图才被注销。该函数不能异常退出。

    HandleForegroundEventL()

    该函数只有当视图处于激活状态下才会被调用,也就是在DoActivateL()调用之后和DoDeactivate()调用之前这段时间。当视图到达前台时,视图将接收到HandleForegroundEventL(ETrue)。当视图从前台被移除时,视图将接受到HandleForegroundEventL(EFalse)。只用视图在前台的状态实际改变时才会调用该函数。因为拥有视图的应用程序可能在前台和后台间来回切换多次,所以该函数会被调用多次。函数的实现可能用来设置焦点或控制屏幕更新。

    HandleCommandL()

    当视图的菜单发出消息事件时时,该函数将调用来处理菜单事件。

    HandleStatusPaneSizeChange()

    由于状态面板的改变导致客户区域大小的变化将调用该函数。

    视图在活动期间接收事件的典型顺序:

    1. DoActivateL()     2. HandleForegroundEventL(ETrue)     3. HandleForegroundEventL(EFalse)     4. DoDeactivate()

    成对出现HandleForegroundEventL()可能在视图活动期间多次调用。DoActivateL()可能在DoDeactivate()调用之前多次调用。

 

1.4.3、视图资源(AVKON_VIEW)

    典型情况下,视图都需要拥有菜单项或CBA。通过将视图资源(AVKON_VIEW)的ID传递给视图的BaseConstructL()方法,可以很容易为每个视图提供自己唯一的菜单项。

    RESOURCE AVKON_VIEW

    {    hotkeys= ;    menubar= ;    cba= ;    }

 

1.4.4、视图切换

    本地视图切换

    本地视图切换就是在同一应用程序内进行视图切换。切换时只需要指定需要切换视图的UID:

    ActivateLocalViewL( TUid::Uid(1) );

    外部视图切换

 

2、事件处理

 

2.1、命令(Commands)事件

    命令事件是由Avkon框架产生,用来响应用户选择菜单项和系统特殊事件。AppUi或Avkon视图将会通过HandleCommandL()方法处理命令事件。

 

2.1.1、AppUi对命令事件的处理

    在传统的应用程序架构中,AppUi的HandleCommandL()方法将处理命令事件。

    void CContainerAppUi::HandleCommandL(TInt aCommand)        switch (aCommand)                case EEikCmdExit:                               Exit();                 break;                        case ECmdXXX:                                // implementation of cut operation                 break;                            ...         default:         break;        }    }

    用户自定义的命令ID(如ECmdXXX)在.hrh文件中定义,Avkon系统命令ID(如EAknSoftKeyBack)定义在avkon.hrh中。EEikCmdExit是系统标准的应用程序退出命令ID。

 

2.1.2、Avkon视图对命令事件的处理

    在视图切换应用程序架构中,当前视图的HandleCommandL()方法将处理命令事件。

    void CMyAppView1::HandleCommandL(TInt aCommand)         switch (aCommand)                 case EMyAppCmdSwitchToView2: 

                {            AppUi()->ActivateLocalViewL(KView2Id);             break; 

                }        case ECmdXXX:                                // Implement cut operation                 break;                        // ... Other view-specific command handling here         case EAknSoftkeyBack:                         ((MEikCommandObserver*)AppUi())->ProcessCommandL(EEikCmdExit);             break;                        default:

                AppUi()->HandleCommandL(aCommand);                 break;             }  

 

2.2、按键事件与控件栈

    按键事件是用户与应用程序交互时键盘所产生的事件。键被按下时被FEP转换成相应的键事件,最终由应用程序框架传递给当前的应用程序。应用程序框架只将键事件传递给在控件栈中的对象。AppUi是缺省的键事件处理对象,但是CCoeControl派生类的UI控件应该第一时间处理键事件。因此必须将控件放入控件栈中,通常情况下由AppUi的AddToStackL()方法将控件放入控件栈中。

    在传统和对话应用程序构架中,在AppUi的构造阶段(Construction()方法)将控件放入控件栈,控件将处于栈顶。当按键事件产生时,应用程序框架首先要求处于栈顶的控件处理事件,如果控件没有处理事件,那么应用程序控件将要求栈中的第二个控件处理,以此类推,当栈中的所以控件都没有处理是,将由AppUi的HandleKeyEventL()方法处理。

    void CMyAppUi::ConstructL()          BaseConstructL();        iCurrentView = CMyAppMainView::NewL(ClientRect());        AddToStackL(iCurrentView); // to enable key events    }

    在视图切换应用程序架构中,控件放入控件栈通常在视图对象的DoActivateL()中控件完成构造后进行。

    void CMyView::DoActivateL(const TVwsViewId&, TUid, const TDesC8&)    {        if(!iUiControl) // iUiControl is CCoeControl-derived UI ctrl        {            iUiControl = CMyUiControl::NewL(this, ClientRect());            AppUi()->AddToStackL(*this, iUiControl); // to ctrl stack.        }    }

    当不希望该控件再接收按键事件时,应该使用AppUi的RemoveFromStack()方法将控件移除控件栈。在视图切换应用程序机构中,通常在视图对象的DoDeactivate()方法中实现从栈中移除控件。

    void CMyView::DoDeactivate()    {        if(iUiControl)        {            AppUi()->RemoveFromStack(iUiControl);

        }        delete iUiControl;        iUiControl = NULL;    }

    在控件栈中的控件响应按键事件是通过调用他们的OfferKeyEventL()方法来实现的。调用的顺序是以控件在控件栈中的顺序进行,最后放入的控件将先调用它的OfferKeyEventL()方法。OfferKeyEventL()方法必须重写,因为它的默认实现不处理任何事件。当控件处理了事件就应返回EKeyWasConsumed,因为如果返回EKeyWasNotConsumed,应用程序框架将使控件栈中的下一个控件来处理。如果所以的控件都返回EKeyWasNotConsumed,那么最后将在AppUi的HandleKeyEventL()方法中处理。

    TKeyResponse CMyUiControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,

                                                                        TEventCode aType)            TKeyResponse response = EKeyWasNotConsumed;          // pass key press events to the listbox. It will typically          // consume Up, Down, and Selection keys.         if (aType == EEventKey && iListBox)                    response = iListBox->OfferKeyEventL(aKeyEvent, aType);                return response;     }