基于parsley的项目前台架构

1.项目简介
    本人准备开发一个信息管理系统,经过详细的考虑,决定采用基于parsley的MVC框架作为FLEX开发的框架。
    parsley的MVC框架的优点
        .适当解耦(视图类和视图model类、控制类与service类),提高了程序的可读性和可维护性
        .避免使用FLEX的事件传播机制,降低了系统运行的风险(过多的注册监听事件会带来意想不到的问题,比如不及时删除无用的事件监听器,会阻止垃圾回收器从而造成内存泄露,而且它们还很难跟踪并且影响程序的性能)
        .适当的对象托管会给编程带来方便
    下图所示:
基于parsley的项目前台架构_第1张图片

    parsley的MVC框架中,一个典型的模块的包分为六个部分:视图包、视图model包、Command包、Model包、Service包、消息包。
    类与类之间的数据传递通过框架提供的消息来完成。
    由于消息类大量的与Model类重复,比如创建用户消息类CreateUserMessage中只有一个类User.从整体上看提高了程序可读性,但是加大了编码工作量,本人决定舍弃消息层,将消息包与Model包合并成Model层,比如CreateUserCommand类的参数直接使用UserModel,而不是CreateUserMessage。
部分代码说明如下:
    <spicefactory:DynamicCommand type="{CreateUserCommand}" messageType="{CreateUserMessage}" />
取消了Message包后,
    <spicefactory:DynamicCommand type="{CreateUserCommand}" messageType="{UserModel}" />

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类注入到视图中,负责管理业务逻辑。
例:
登录视图类代码片段:
    <mx:Script>
        <![CDATA[
            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中
            }

        ]]>
    </mx:Script>
    
    <mx:Panel horizontalCenter="0"
              verticalCenter="0">
        <mx:Form
            keyDown="handleKeyDown( event )">
            <mx:FormItem label="name">
                <mx:TextInput 
                    id="usernameInput"
                    text="{ pm.username }"/>  //数据封装在视图model类中
            </mx:FormItem>
            <mx:FormItem label="password">
                <mx:TextInput 
                    id="passwordInput" 
                    text="{ pm.password }"
                    displayAsPassword="true"/>
            </mx:FormItem>
        </mx:Form>
        
        <mx:CheckBox
            label="Model injected?"
            labelPlacement="left"
            enabled="false"
            selected="{ pm != null }"/>
        
        <mx:Button 
            label="login"
             click="button1_clickHandler(event)"/>
    </mx:Panel>

视图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 );
        }
        
        
    }
在配置文件中必须设置动态命令标签:
    <spicefactory:DynamicCommand type="{LoginCommand}" />

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;
    }

转自:http://blog.chinaunix.net/space.php?uid=122937&do=blog&id=143083

你可能感兴趣的:(架构)