阅读 2035

MVP那些事儿(6)MVC转化为MVP

目录

MVP那些事儿(1)……用场景说话

MVP那些事儿(2)……MVC架构初探

MVP那些事儿(3)……在Android中使用MVC(上)

MVP那些事儿(4)……在Android中使用MVC(下)

MVP那些事儿(5)……中介者模式与MVP的关系

MVP那些事儿(6)……MVC变身为MVP

MVP那些事儿(7)……Repository设计分析

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

新年尬聊

快速回顾

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

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

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

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

什么是中介者? MVP那些事儿(5)中介者与MVP 欢迎回顾。

中介者的职责,隔离

那么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的生命周期控制,这些都需要大家根据实际需求去填充了,后天就是除夕了,马上就要过节了,好开心,大家都好好多陪陪家人吧,工作什么的都去见鬼吧,哈哈哈,我们节后再继续。

关注下面的标签,发现更多相似文章
评论