一、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没有固定的写法,结合需求,写出适合项目的分层处理架构才是王道