MVC框架模式在移动开发中的实践

一、MVC框架模式介绍:

  • MVC (Model View Controller),是模型(model)视图(view)控制器(controller)的缩写,一种软件设计模式,用于组织代码用一种功能模块和数据模块分离的方法
    层次角色职责划分如下:
  • Model:模型层,负责处理数据的加载或者存储
  • View:视图层,负责界面数据的展示,与用户进行交互
  • Controller:控制器层,负责逻辑业务的处理

二、在android、ios中的 角色 划分:

这里写图片描述

三、例子演示
场景:点击一个按钮,模拟从网络上拉取图片,并显示出来
详细情见:代码演示

  • android版本
  • BaseModel 代码,本层主要封装业务处理基类。
public abstract class BaseModel {

    /**
     * 本接口主要处理一些数据模型的初始化
     */
    protected abstract void initData();


    /**
     * 回收数据模型资源
     */
    public abstract void recycRes();

}
  • GetNetImgModel处理获取网络图片的 代码如下
public class GetNetImgModel extends BaseModel {

    @Override
    protected void initData() {

    }

    public int getNetImg(){

        return R.mipmap.ic_launcher;
    }

    @Override
    public void recycRes() {

    }

    /**
     * 加载监听器
     * @param <T>
     */
    public interface LoadListener<T>{

        void onSuccess(T msg);
        void onError(String tips);
    }
}
  • BaseView 负责数据的显示,本类为基类
public abstract class BaseView {

    protected WeakReference<BaseController> mContext;
    /**
     * 响应生命周期,子类需要重写
     */
    public abstract void initView(BaseController conttext);

    /**
     * 子类需要重写
     * @return
     */
    public abstract int getLayout();


    /**
     * 子类需要重写 ,生命周期中回收资源接口
     * @return
     */
    public abstract void recycRes();

}
  • GetNetImgView 显示获取网络图片的视图层
public class GetNetImgView extends BaseView implements View.OnClickListener{

    private Button getNetImgBtn;
    private ImageView resultImg;
    private UserActionListener mUserActionListener;

    public void bindUserActionListener(UserActionListener listener){
        this.mUserActionListener = listener;
    }

    @Override
    public void initView(BaseController conttext) {
        mContext = new WeakReference<BaseController>(conttext);
        getNetImgBtn = (Button)mContext.get().findViewById(R.id.btn_getnetimg);
        getNetImgBtn.setOnClickListener(this);
        resultImg = (ImageView)mContext.get().findViewById(R.id.img_result);
    }

    @Override
    public int getLayout() {
        return R.layout.activity_main;
    }

    public void setImage(int resId){
        if(resultImg != null){
            resultImg.setBackgroundResource(resId);
        }
    }

    @Override
    public void recycRes() {
       System.out.println("41---------此处回收资源处理");
    }

    @Override
    public void onClick(View view) {
        if(this.mUserActionListener != null){
            this.mUserActionListener.onClick(view);
        }
    }

    /**
     * 用户交互事件
     */
    public interface UserActionListener{
        void onClick(View view);
    }
}
  • BaseController 控制器基类
public abstract class BaseController<M extends BaseModel,V extends BaseView> extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getModel();
        setContentView(getView().getLayout());
        getView().initView(this);
    }

    public abstract M getModel();

    public abstract V getView();


    @Override
    protected void onDestroy() {
        super.onDestroy();
        getView().recycRes();
        getModel().recycRes();
    }
}
  • MainActivity获取网络图片的控制器
public class MainActivity extends BaseController<GetNetImgModel,GetNetImgView> implements GetNetImgView.UserActionListener{

    private GetNetImgView mView;
    private GetNetImgModel mModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public GetNetImgModel getModel() {
        if(mModel == null){
            mModel = new GetNetImgModel();
        }
        return mModel;
    }

    @Override
    public GetNetImgView getView() {
        if(mView == null){
            mView = new GetNetImgView();
            mView.bindUserActionListener(this);
        }
        return mView;
    }


    @Override
    public void onClick(View view) {
        mView.setImage(mModel.getNetImg());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mModel != null){
            mModel = null;
        }
        if(mView != null){
            mView = null;
        }
    }
}
  • 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.liuxiaobing.mvcdemo.MainActivity">

    <Button
        android:id="@+id/btn_getnetimg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="获取图片"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/img_result"
        android:layout_width="100dp"
        android:layout_height="100dp" />

</LinearLayout>
  • IOS 版本

  • BaseModel

.h  文件

#import <Foundation/Foundation.h>



/**
 MVC 层的业务逻辑层,主要用来处理数据逻辑,并用将处理结果丢给Controller层
 */
@interface BaseModel : NSObject


/**
 初始化数据
 */
-(void) initData;


/**
 回收数据对象
 */
-(void) recyDataRes;



@end


.m文件 

#import "BaseModel.h"

@implementation BaseModel

-(void) initData{

}

- (void)recyDataRes{

}

@end
  • BaseView 代码
#import <UIKit/UIKit.h>


/**
 MVC 模式中的view层,本层的角色职责在于:
 1.主要用来显示数据
 2.其中也负责暂存一些 临时数据
 本类为视图基类
 */

@class BaseModel;
@class BaseData;
@interface BaseView : UIView


/**
 初始化视图
 */
-(void) initView;


/**
 刷新视图

 @param model 待刷新的数据,其中数据是由model传进来
 */
-(void) refreshViewWithModel:(BaseModel *) model;


/**
 在view层直接访问data对象

 @param data data对象还是由 Model层传进来
 */
-(void) refreshViewWithData:(BaseData *) data;



/**
 回收视图层的资源
 */
-(void) recycView;



@end
  • BaseView.m
#import "BaseView.h"

@implementation BaseView


-(void) initView{

}

- (void)refreshViewWithData:(BaseData *)data{

}
- (void)refreshViewWithModel:(BaseModel *)model{

}

- (void)recycView{

}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
  • GetNetImgView.h
//
//  GetNetImgView.h
//  MVCDemo
//
//  Created by liuxiaobing on 2018/8/2.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import "BaseView.h"


@protocol ViewClickListener
@optional
-(void) onClickListener:(UIView*)view;

@end



@interface GetNetImgView : BaseView

@property(nonatomic,strong) UIButton *getNetImgBtn;
@property(nonatomic,strong) UIImageView* resultView;
@property(nonatomic,weak) id<ViewClickListener> clickDelegate;





/**
 设置图片

 @param imgUrl 图片url
 */
-(void) setImage:(NSString *) imgUrl;

@end
  • BaseControllter.h
//
//  BaseController.h
//  MVCDemo
//
//  Created by liuxiaobing on 2018/8/2.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import <UIKit/UIKit.h>


@class BaseView;
@class BaseModel;

@interface BaseController : UIViewController


/**
 获取数据模型对象,需要重载

 @return 对应的model对象
 */
-(BaseModel *) getModel;


/**
 获取视图层对象,子类需要重载

 @return 对应的视图层对象
 */
-(BaseView *) getView;




@end
  • BaseControllr.m
//
//  BaseController.m
//  MVCDemo
//
//  Created by liuxiaobing on 2018/8/2.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import "BaseController.h"
#import "BaseModel.h"
#import "BaseView.h"

@interface BaseController ()

@end

@implementation BaseController

- (void)viewDidLoad {
    [super viewDidLoad];

}

-(BaseModel *) getModel{
    NSLog(@"getModel 本接口子类需要重载,因为我是父类我找不到你们具体的共性,所以我不处理具体的业务");
    return nil;
}

-(BaseView *) getView{
     NSLog(@"getView 本接口子类需要重载,因为我是父类我找不到你们具体的共性,所以我不处理具体的业务");
    return nil;
}


/**
 控制器销毁的时候,对model与view对象也进行回收
 */
-(void) dealloc{

    if([self getModel]){
        [[self getModel] recyDataRes];
    }
    if([self getView]){
        [[self getView] recycView];
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

}


@end
  • ViewController.h
//
//  ViewController.h
//  MVCDemo
//
//  Created by liuxiaobing on 2018/8/2.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "BaseController.h"
#import "GetNetImgView.h"

@class GetNetImgModel;

@interface ViewController : BaseController<ViewClickListener>

@property(nonatomic,strong) GetNetImgModel *imgModel;
@property(nonatomic,strong) GetNetImgView *imgView;

@end

  • ViewController.m
//
//  ViewController.m
//  MVCDemo
//
//  Created by liuxiaobing on 2018/8/2.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import "ViewController.h"
#import "GetNetImgModel.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[self getModel] initData];
    [self getView];

}
- (BaseModel *)getModel{
    if(!self.imgModel){
        self.imgModel = [[GetNetImgModel alloc] init];
        [self.imgModel initData];
    }
    return self.imgModel;
}

- (BaseView *)getView{

    if(!self.imgView){
        self.imgView = [[GetNetImgView alloc] init];
        [self.imgView initView];
        self.imgView.clickDelegate = self;
        self.imgView.frame = CGRectMake(0, 20, [ UIScreen mainScreen ].bounds.size.width, [ UIScreen mainScreen ].bounds.size.height - 20);
        [self.view addSubview:self.imgView];

    }
    return self.imgView;
}

#pragma 实现点击 协议
-(void) onClickListener:(UIView *)view{

    NSString* imgUrl = [(GetNetImgModel *)[self getModel] getNetImg];
    [(GetNetImgView *)[self getView] setImage:imgUrl];
}

- (void)dealloc{
    if(self.imgView){
        self.imgView = nil;
    }
    if(self.imgModel){
        self.imgModel = nil;
    }
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

}


@end

四、优缺点分析
优点:

  • 耦合性低,数据与视图解耦
  • 重用性高
  • 生命周期成本低
  • 部署快
  • 可维护性高
  • 有利软件工程化管理

缺点

  • 没有明确的定义,往往没有严格的分层定义
  • 不适合小型,中等规模的应用程序
  • 增加系统结构和实现的复杂性
  • 视图与控制器间的过于紧密的连接
  • 视图对模型数据的低效率访问
  • 一般高级的界面工具或构造器不支持模式

五、与MPV模式的对比——请听下次分解

六、小结

  • MVC模式并不是一种规定,而是对程序作分层的一种编程思想,所以MVC没有固定的写法,结合需求,写出适合项目的分层处理架构才是王道

猜你喜欢

转载自blog.csdn.net/d06110902002/article/details/81362802