博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MVP那些事儿(6)MVC转化为MVP
阅读量:5998 次
发布时间:2019-06-20

本文共 5103 字,大约阅读时间需要 17 分钟。

目录

马上就要过春节了,现在还在单位刷掘金的同学,可见你们在领导的心目中是何其重要,在这里,首先祝大家新春快乐、万事如意,新年新气象,来年再创新高!

快速回顾

前面花了大量的篇幅去介绍分层架构的相关知识点,以及MVC架构是如何实现的,上一篇介绍了中介者模式与MVP间的关系,这期间应用了大量的场景描述,比如租房子的故事,项目开发的故事,加班的故事,这些铺垫都是为了能讲明白MVP,更是为了在以后的实战中能更加自由的去扩展和设计出新的变种,在项目中熟练应用,这就需要知其然,知其所以然。

这一篇的能容比较单一,如何去设计一个MVP,因为有之前的铺垫,我们直接用MVC的例子进行改写。

首先回顾一下MVC和MVP的区别,看下面这两张设计图,经过之前反复多次的总结和归纳,得出一个结论:

在MVC中,C的职责非常的单一,就是负责处理流程控制的,而在MVP中除了负责流程控制外,它还要负责M与V之间的一个隔离的作用,是作为一个中介者存在的。

什么是中介者? 欢迎回顾。

中介者的职责,隔离

那么MVP的本质上就是中介者,从上面的结论中不难看出,只要让Controller赋予了中介者的职能,那么它就会变为Presenter。

隔离就意味着,在设计的过程中,M和V之间是不能相互引用的,那么所有的交互都需要通过Controller去完成的,只要满足了这点,Controller就会升级为Presenter。我们把之前的MVC调用方式的代码搬出来,从应用层倒推设计:

public class MainActivity extends AppCompatActivity implments TasksView{    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化Controller,this就是View,通过构造器注入        TasksController controller = new TasksController(tasksView:this);                //初始化Model,Model -> View and View -> Model        TasksRepository model = new TasksRepository(tasksView:this);                //Controller -> Model        model.setController(controller);    }}复制代码

这一段代码是前几章中示例MVC中用到的,可以看到,在初始化TaskRepository时,通过构造函数将view注入到了TaskRepository,而这里的TaskRepository就是Model层的实例。我们讲过,在MVP中,M与V不能以任何形式见面,可见上面的写法在MVP中是不允许的,所以需要重新设计,不允许View以各种形式出现在Moodel中,这其中就包括依赖注入的三种方式。其次,由于MainActivity是View的具体实现,很显然它实现了TaskView,虽然TaskView在设计中并没有刻意的去包含Model,但却无法控制其子类包含有Model,这里TaskRepository在MainActivity中实例化了,它们一个代表着M,一个代表着V,但是在这里,其实并不会对整体设计带来影响,毕竟子类的行为是不受控制的,但为了规范使用,一般情况下Model的初始化是放在Presenter的实例中。在我看来这其实还是有点好处,Presenter会去处理Model的初始化,这样,当View想使用不同的Model时,直接去使用不同Presenter即可。经过简单的分析,代码这样去修改

public class MainActivity extends AppCompatActivity implments TasksView{    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化Controller,this就是View,通过构造器注入        TasksController controller = new TasksController(tasksView:this);    }}/** 由于TasksController中public class TasksController implements Observer{        public TasksController(TasksView view) {        //通过构造函数接收view        this.view = view;        //通过构造函数初始化Model        TasksRepository model = new TasksRepository();        //Controller -> Model        model.addObserver(observer: this);    }   .   .   .}复制代码

通过以上的改造,Controller就变成了Presenter,别忘记修改类名,在真实的项目中,各个层大多是以接口的形式定义的,这一点都不奇怪,没有接口哪里来的设计,所以别忘了做接口设计,在层的设计中,都是通过具体业务反推而来的,凭空想象是不可取的,如果有一定的积累和经验,可以先设计出来几个通用接口,然后再慢慢完善,比如Model加载数据的功能是比不可少的,那么可以先定义出loadData,比View接收到Presenter的通知,处理视图的方法,再比如Prensenter统一处理发起获取数据的请求等等。而这些具体业务的接口,才是MVP框架丰满的关键,但前提是我们一定要去遵循MVP架构的原则去设计,那么接下来,我们尝试这去设计这些接口。

设计接口,让MVP框架变的更加强壮

框架即为骨骼,而接口和它的实现则是肌肉系统,接口决定了肌肉的走向,而实现则决定了肌肉的能力。

场景

在最近的工作中,有这么一个需求,就是需要在App中同时存在http的请求和tcp的请求: 由于我不知道我获取的具体是什么东西,所以起名为getObject,同时我也不清楚具体参数和返回值(先忽略太多具体的业务)。

让我们一起从头撸一个MVP框架

1、定义Model

public interface DataSource {    void getObject();}复制代码

2、定义Presenter

public interface Presenter {    void loadSometing();}复制代码

3、定义View

public interface View {    void setPresenter(Presenter p);}复制代码

4、定义Presenter与Model间的监听

public interface PresenterListener {    void onSametingCallBack()}复制代码

首先实现Model

1、http请求的Model

public class RemoteHttpRepository implements DataSource {    @override    void getObject() {        //执行http请求    }}复制代码

2、tcp请求的Model

public class RemoteTcpRepository implements DataSource {    @override    void getObject() {        //执行tcp请求        ..        if(listener != null) {            listener.onSametingCallBack();        }    }        void addListener(PresenterListener listener) {            }}复制代码

实现View

public abstruct class BaseView implements View {    Presenter presenter;    void setPresenter(BasePresenter presenter) {        this.presenter = presenter    }        abstruct onViewDoSamething();}复制代码

实现 Presenter

public class BasePresenter implements Presenter ,PresenterListener{    RemoteTcpRepository repository;    View view;    public BasePresenter (View view) {        this.view = view;        //这里使用TCP请求        repository = new RemoteTcpRepository();        repository.addListener(presenterListener: this);    }    @Override    void loadSomething() {        repository.getObject();    }        @Override    void onSametingCallBack() {        view.onViewDoSamething();    }}复制代码

当然别忘了加入监听,上面的BasePresenter实现了监听,我们在之前的章节介绍详细的介绍过监听的部分。

How To Use

public class MainActivity extends AppCompatActivity implments BaseView{        @Override        public void onCreate(@Nullable Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            Presenter presenter = new BasePresenter(view: this);            presenter.loadSamething();        }                @Override        void onViewDoSamething() {            //do view         }    }复制代码

接口的定义要根据具体的业务去具体定义,上面的例子就是非常具体的业务去决定了接口的定义,所以,千万不要照葫芦画瓢,关键是要理解思想。

总结

到此为止整个MVP的“肌肉”雏形就出来了,我们继续向里面添加内容:比如,添加泛型对象、实现具体的网络请求功能、是否支持数据缓存、以及Presenter的生命周期控制,这些都需要大家根据实际需求去填充了,后天就是除夕了,马上就要过节了,好开心,大家都好好多陪陪家人吧,工作什么的都去见鬼吧,哈哈哈,我们节后再继续。

转载地址:http://zozmx.baihongyu.com/

你可能感兴趣的文章
delphi中,让程序只运行一次的方法[1]
查看>>
常见Serialize技术探秘(ObjectXXStream、XML、JSON、JDBC byte编码、Protobuf)
查看>>
构筑敏捷能力中心,打造下一代数字银行“操作系统”!
查看>>
oracle 修改 system 密码
查看>>
Java中运用数组的四种排序方法
查看>>
Jfinal 学习控制台打印方法
查看>>
AngularJs初识
查看>>
带着三个问题深入浅出React高阶组件
查看>>
点石成金-Linux目录结构,命令,文件类型学习
查看>>
16. php-fpm配置相关
查看>>
处理图形中的乱码
查看>>
安装软件包
查看>>
linux磁盘分区丶挂载和卸载与格式化
查看>>
cobbler简概
查看>>
Objective-C中runtime机制的应用
查看>>
Tomcat日志中文乱码问题解决
查看>>
云搜索服务在日志解决方案的应用
查看>>
Jersey 2.x 分支 Java SE 兼容性
查看>>
PHP执行效率高zblog-asp为什么还有生存的空间?[图]
查看>>
国内有哪些可在室内外都能使用的激光雷达?
查看>>