mvc mvp mvvm

一:MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用。

1:MVC

  • 视图(View):用户界面。
  • 控制器(Controller):业务逻辑
  • 模型(Model):数据保存
  • 通讯方式(MVC与Android的各个组件的对应关系)
    1. View 自定义View或ViewGroup,负责将用户的请求通知Controller,并根据model更新界面
    2. Controller 完成业务逻辑后,Activity或者Fragment,接收用户请求要求 Model 改变状态
    3. Model 将新的数据发送到 View,用户得到反馈

2、互动模式:接受用户指令时,MVC 可以分成两种方式。一种是通过 View 接受指令,传递给 Controller。
另一种是直接通过controller接受指令。

3、实例用法:

1. 用户可以向 View 发送指令(DOM 事件),再由 View 直接要求 Model 改变状态。

2. 用户也可以直接向 Controller 发送指令(改变 URL 触发 hashChange 事件),再由 Controller 发送给 View。

3. Controller 非常薄,只起到路由的作用,而 View 非常厚,业务逻辑都部署在 View。所以,Backbone 索性取消了 Controller,只    保留一个 Router(路由器) 。



  View实现:

复制代码
public class TrackCtrlView implements View.OnClickListener{
    private ImageView btnStartTrack, btnStopTrack, btnPauseTrack;
    private TrackCtrlViewListener listener;
    private TrackRecordInfo trackRecordInfo;


    public TrackCtrlView(Activity activity, TrackCtrlViewListener listener){
        this.listener = listener;
        btnStartTrack = (ImageView) activity.findViewById(R.id.btnStartTrack);
        btnStopTrack = (ImageView) activity.findViewById(R.id.btnStopTrack);
        btnPauseTrack = (ImageView) activity.findViewById(R.id.btnPauseTrack);
        btnStartTrack.setOnClickListener(this);
        btnStopTrack.setOnClickListener(this);
        btnPauseTrack.setOnClickListener(this);
        btnPauseTrack.setOnClickListener(this);
    }

    /**
     * 将用户请求通知Controller
     */
    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.btnStartTrack:
                if(listener != null){
                    listener.trackStatusRequest(TrackRecordStatus.Recording);
                }
                break;

            case R.id.btnStopTrack:
                if(listener != null){
                    listener.trackStatusRequest(TrackRecordStatus.Stoped);
                }
                break;

            case R.id.btnPauseTrack:
                if(listener != null){
                    if(trackRecordInfo.status == TrackRecordStatus.Paused){
                        listener.trackStatusRequest(TrackRecordStatus.Recording);
                    }else{
                        listener.trackStatusRequest(TrackRecordStatus.Paused);
                    }
                }
                break;

            default:

                break;
        }
    }

    private void refreshView(){
        TrackRecordStatus trackStatus = trackRecordInfo == null ?
                TrackRecordStatus.Stoped : trackRecordInfo.status;
        if (trackStatus == TrackRecordStatus.Recording) {
            btnStartTrack.setVisibility(View.GONE);
            btnPauseTrack.setVisibility(View.VISIBLE);
            btnStopTrack.setVisibility(View.VISIBLE);
            btnPauseTrack.setImageResource(R.drawable.btn_track_ctrl_pause);

        } else if (trackStatus == TrackRecordStatus.Paused) {
            btnStartTrack.setVisibility(View.GONE);
            btnPauseTrack.setVisibility(View.VISIBLE);
            btnStopTrack.setVisibility(View.VISIBLE);
            btnPauseTrack.setImageResource(R.drawable.btn_track_ctrl_resume);

        } else {
            // TrackRecordStatus.Stoped
            btnStartTrack.setVisibility(View.VISIBLE);
            btnPauseTrack.setVisibility(View.GONE);
            btnStopTrack.setVisibility(View.GONE);
        }
    }

   public void setTrackRecordInfo(@Nullable TrackRecordInfo trackRecordInfo) {
        this.trackRecordInfo = trackRecordInfo;
        refreshView();
    }

    public interface TrackCtrlViewListener{
        /**
         * 用户点击按钮
         */
        public void trackStatusRequest(@Nullable TrackRecordStatus newStatus);
    }
}
复制代码

 

  Model实现:

复制代码
public class TrackRecordInfo {
    private static final Gson gson = new Gson();

    /**
     * 应该是保存轨迹数据库id,此demo中数据库操作不实现,暂时trackId一直为0
     */
    public int trackId;

    public TrackRecordStatus status;

    public TrackRecordInfo(int trackId, TrackRecordStatus status) {
        this.trackId = trackId;
        this.status = status;
    }

    @NonNull
    public static TrackRecordInfo loadTrackRecordInfo(@NonNull Context context){
        String pref = SpUtil.getString(context, SpUtil.KEY_TRACK_RECORD_INFO, "");
        if(!TextUtils.isEmpty(pref)){
            return gson.fromJson(pref, TrackRecordInfo.class);
        }
        return null;
    }

    public static void changeTrackRecordInfo(@NonNull Context context, @Nullable TrackRecordInfo info){
        SpUtil.saveString(context,
                SpUtil.KEY_TRACK_RECORD_INFO,
                info == null ? "" : gson.toJson(info));

        //model通过消息总线,通知View刷新
        EventBus.getDefault().post(new EventTrackRecordInfoChanged(info));
    }
}
复制代码

 

  Controller实现:

复制代码
public class MainActivity extends ActionBarActivity implements TrackCtrlView.TrackCtrlViewListener{
    private TrackCtrlView trackCtrlView;
    private TrackRecordInfo trackRecordInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        trackCtrlView = new TrackCtrlView(this, this);

        EventBus.getDefault().register(this);

        trackRecordInfo = TrackRecordInfo.loadTrackRecordInfo(this);
        trackCtrlView.setTrackRecordInfo(trackRecordInfo);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        EventBus.getDefault().unregister(this);
    }


    @Override
    public void trackStatusRequest(@Nullable TrackRecordStatus newStatus) {
        if(newStatus == TrackRecordStatus.Recording){
            int trackId = 0;  //在数据库创建一条轨迹,并获取到数据库id
            trackRecordInfo = new TrackRecordInfo(trackId, TrackRecordStatus.Recording);

        }else if (newStatus == TrackRecordStatus.Paused) {
            if(trackRecordInfo != null){
                trackRecordInfo.status = newStatus;
            }

        } else {
            trackRecordInfo = null;
        }
        TrackRecordInfo.changeTrackRecordInfo(this, trackRecordInfo);
    }

    public void onEventMainThread(EventTrackRecordInfoChanged event){
        trackRecordInfo = event.info;
        trackCtrlView.setTrackRecordInfo(trackRecordInfo);
    }

}
复制代码

 

  最后总结下3者之间的关系:

  

    Android中,model通知view改变,可以通过消息总线实现。

二:MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

1. 各部分之间的通信,都是双向的。

2. View 与 Model 不发生联系,都通过 Presenter 传递。

3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

至此为止,通过 MVP+RxJava 的组合,我们已经构建出一个比较灵活的 Android 项目框架,总共分成了四部分:View 层,Presenter 层,Model 业务层,Data 数据持久化层。这个框架的优点大概有以下几点:

  • 每层各自独立,通过接口通信
  • 实现与接口分离,不同场景(正式,测试)可以挂载不同的实现,方便测试和开发写假数据
  • 所有的业务逻辑都在非UI线程中进行,最大限度减少IO操作对UI的影响
  • 使用 RxJava 可以将复杂的调用进行链式组合,解决多重回调嵌套问题

三:MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。Angular和 Ember 都采用这种模式。

猜你喜欢

转载自blog.csdn.net/u012970106/article/details/78779978