目录
马上就要过春节了,现在还在单位刷掘金的同学,可见你们在领导的心目中是何其重要,在这里,首先祝大家新春快乐、万事如意,新年新气象,来年再创新高!
快速回顾
前面花了大量的篇幅去介绍分层架构的相关知识点,以及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的生命周期控制,这些都需要大家根据实际需求去填充了,后天就是除夕了,马上就要过节了,好开心,大家都好好多陪陪家人吧,工作什么的都去见鬼吧,哈哈哈,我们节后再继续。