1.项目简介 本人准备开发一个信息管理系统,经过详细的考虑,决定采用基于parsley的MVC框架作为FLEX开发的框架。
parsley的MVC框架的优点
.适当解耦(视图类和视图model类、控制类与service类),提高了程序的可读性和可维护性
.避免使用FLEX的事件传播机制,降低了系统运行的风险(过多的注册监听事件会带来意想不到的问题,比如不及时删除无用的事件监听器,会阻止垃圾回收器从而造成内存泄露,而且它们还很难跟踪并且影响程序的性能)
.适当的对象托管会给编程带来方便
下图所示:
parsley的MVC框架中,一个典型的模块的包分为六个部分:视图包、视图model包、Command包、Model包、Service包、消息包。
类与类之间的数据传递通过框架提供的消息来完成。
由于消息类大量的与Model类重复,比如创建用户消息类CreateUserMessage中只有一个类User.从整体上看提高了程序可读性,但是加大了编码工作量,本人决定舍弃消息层,将消息包与Model包合并成Model层,比如CreateUserCommand类的参数直接使用UserModel,而不是CreateUserMessage。
部分代码说明如下:
取消了Message包后,
2.项目目录结构src
--默认包
--index.mxml //首页面
--Config.mxml //根配置文件
--com.teacherHome
--system
--config
--SystemConfig.mxml //系统管理模块配置文件
--commands
--CreateXsCommand.as //创建学生命令
--DeleteBjCommand.as //删除班级命令
--models
--LoginModel.as //登录数据类
--XsModel.as //学生数据类
--BjModel.as //班级数据类
--Services
--XsSevice.as //学生远程服务类
--BjService.as //班级远程服务类
--mock
--XsServiceMock.as //学生服务测试类
--BjServiceMock.as //班级服务测试类
--view
--components
--CjPanel.mxml //成绩组件
--renderers
--ImageRenderer.mxml //Render组件
--skins
--CjListSkin.mxml //成绩列表皮肤组件
SystemMain.mxml //系统管理主页面
--styles
--System.css //系统管理的CSS文件
3.视图包与视图model包 视图类负责组织页面的组件显示,只包含组件和组件事件处理函数。视图model类注入到视图中,负责管理业务逻辑。
例:
登录视图类代码片段:
import com.adobe.system.view.LoginPM;
[Bindable]
[Inject]
public var pm : LoginPM;//视图model类
private function handleKeyDown( event : KeyboardEvent ) : void
{
if( event.keyCode == Keyboard.ENTER )
{
pm.username=usernameInput.text;
pm.password=passwordInput.text;
pm.login(username, password);
}
}
protected function button1_clickHandler(event:MouseEvent):void
{
pm.login(username, password); //业务逻辑也封装在视图model中
}
]]>
verticalCenter="0">
keyDown="handleKeyDown( event )">
id="usernameInput"
text="{ pm.username }"/> //数据封装在视图model类中
id="passwordInput"
text="{ pm.password }"
displayAsPassword="true"/>
label="Model injected?"
labelPlacement="left"
enabled="false"
selected="{ pm != null }"/>
label="login"
click="button1_clickHandler(event)"/>
视图model类
public class LoginPM
{
public var username : String="good";
public var password : String="bad";
public var isinit:Boolean=false;
[init]
public function LoginPM():void
{
isinit=true;
}
[MessageDispatcher] public var sendMessage:Function; public function setUsername( username : String ) : void
{
this.username = username;
}
public function setPassword( password : String ) : void
{
this.password = password;
}
public function login( username:String, password:String ):void {
if( username != '' && password != '' ) {
message = '';
var loginMessage:LoginMessage = new LoginMessage( username, password );
sendMessage( loginMessage ); //派发消息
}
}
//接收登录处理结果,当Commandod类的方法result处理完成后,自动派发CommandResult命令
[CommandResult(type="com.messages.LoginMessage")]
public function handleResult() : void {
if( session.loggedIn ) {
mainPresentationModel.switchTo( Constants.STATE_DASHBOARD );
}
else {
message = ResourceManager.getInstance().getString(
'General', 'loginFailed' );
}
}
//当Commandod类的方法error处理完成后,自动派发CommandError命令
[CommandError(type="com.messages.LoginMessage")]
public function handleError():void {
message = ResourceManager.getInstance().getString(
'General', 'serviceFailed' );
}
}
4.Command包 一个服务对应着一个Command类,比如CreateUserCommand,LoadUsersCommand。
例子代码:
public class LoginCommand {
[Inject]
public var loginService:IUserService;
[Inject]
public var session:Session;
private static const logger:Logger = LogContext.getLogger( LoginCommand );
public function execute( message:LoginMessage ):AsyncToken {
return loginService.login( message.username, message.password );
}
public function result ( user:User ) : void {
if( user != null ) {
session.loggedIn = true;
session.user = user;
}
else {
session.loggedIn = false
}
}
public function error (fault:Fault) : void {
logger.error( "service call failed: " + fault.message );
}
}
在配置文件中必须设置动态命令标签:
5.Service包 Service类负责与后台进行交互,从WEB服务器或数据库获取数据。
模拟后台调用代码如下:
public class UserService implements IUserService {
private var user:User;
private var mockServiceUtil:MockServiceUtil = new MockServiceUtil;
public function LoginServiceMock() {
user = new User();
user.id = "1";
user.firstname = "Jochen";
user.lastname = "Hilgers";
}
public function login(username:String, password:String):AsyncToken {
return mockServiceUtil.createToken( user );
}
6.Model包 model类负责封装对象的属性,model类主要分为二种:一、实体对象,比如用户UserModel,班级BjModel等;二、传递的消息,比如登录事件中传递的LoginMessage。
例子:
public class LoginMessage {
public var username:String;
public var password:String;
public function LoginMessage( username:String, password:String ) {
this.username = username;
this.password = password;
}
}
[RemoteClass(alias="com.model.User")]
public class User {
public var id:String;
public var firstname:String;
public var lastname:String;
}