一個好的好的設(shè)計模式可以幫我們很好的管理我們的代碼褒脯,也會方便于我們的后期的擴展缆毁。特別是針對我們這樣的新手,學(xué)好一個好的代碼管理是很有必要的颁督。所以今天浇雹,和大家一起學(xué)習(xí)一下MVP模式。
一吠裆、MVP設(shè)計模式概述
什么是MVP設(shè)計模式
MVP,分別是Model-View-Presenter,即模型-視圖-提出者硫痰。
Model:模型,實現(xiàn)業(yè)務(wù)邏輯和實例生成非春。
View:視圖缓屠,對應(yīng)的界面布局,以及界面布局的方法储耐。
Presenter:一個活動中滨溉,主要的業(yè)務(wù)交互,作為view和model的中間傳達者闽撤。
什么是MVC設(shè)計模式
MVP脯颜,分別是Model-View-Presenter,即模型-視圖-控制器。
Model:模型闸餐,實現(xiàn)業(yè)務(wù)邏輯和實例生成矾芙。
View:視圖,對應(yīng)的界面布局蠕啄,以及界面布局的方法歼跟。
Controllor:作為頁面的控制器格遭,響應(yīng)view的交互,對應(yīng)于Android中的Activity
對比
這么說可能不是很清晰拒迅,我們用兩張圖片來描述一下。
但是在Android我們的可以知道硬梁,其實Avtivity不僅要處理view的呈現(xiàn)胞得,還要負責(zé)處理頁面的業(yè)務(wù)邏輯,顯得Activity不僅像view阶剑,又像controllor的結(jié)合體牧愁,導(dǎo)致Acitivity整體臃腫,超過1000行都是常事猪半。
所以,為了更好的解耦這樣的情況沽甥,讓Activity更好的只關(guān)心頁面的呈現(xiàn)俐填,將主要的業(yè)務(wù)交互放置在presenter中實現(xiàn),讓Presenter作為view與model的中間傳遞者盏檐。減少Activity的體積驶悟。降低耦合度。
在MVP模式中硫豆,我們要做到笼呆,view層和model不能直接通信,要想通信汗茄,必須通過Persenter這一中間件铭若。并且递览,view瞳腌,model,presenter都是接口儿捧,之間的通訊也都是通過接口實現(xiàn)的吵冒。
二、 MVP的簡單實現(xiàn)
接下來我們通過一個基礎(chǔ)的實例亿汞,讓我們來實現(xiàn)一個簡單的MVP模式的登錄界面揪阿。從實例的角度,我們來分析一個具體的MVP模式吴裤∧缃。看看他是怎樣實現(xiàn)解耦,以及明顯的內(nèi)容劃分剖膳。
Model層:
model層是用來實現(xiàn)某一層里面的業(yè)務(wù)邏輯岭辣。
那么,在一個登錄界面中仑濒,我的model層就是實現(xiàn)登錄密碼檢驗的功能偷遗。
首先,我們需要有一個對象類矗烛,來表達我們需要檢驗的對象箩溃。
public class User {
private String name;
private String password;
public User(String name,String password){
this.name = name;
this.password = password;
}
...省略getter和setter
}
然后我們需要一個LoginModel的接口函數(shù),來申明我們的登錄所需要的函數(shù)歪架。
public interface LoginModel {
void login(User user);
}
其次是model的實現(xiàn)類霹陡,實現(xiàn)我們剛才在LoginModel中申明的login函數(shù)。
這里我們延時2秒鐘攒霹,用于模擬登陸效果浆洗。
public class LoginModelImpl implements LoginModel{
@Override
public void login(User user) {
final String name = user.getName();
final String password = user.getPassword();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Boolean error =false;
if (TextUtils.isEmpty(name)){
error = true;
//輸入錯誤
System.out.println("輸入錯誤");
}
if (TextUtils.isEmpty(password)){
error = true;
//輸入錯誤
System.out.println("輸入錯誤");
}
if(!error){
//登錄成功
System.out.println("登錄成功");
}
}
},2000);
}
}
View層:
對應(yīng)的界面布局伏社,以及界面布局的方法。
這里我們需要實現(xiàn)的waitDialog的顯示與消失速妖,以及登錄成功和失敗的提醒聪黎,所以建立我們的view接口類,LoginView.
public interface LoginView {
void loginSuccess();
void ErrorPass();
void ErrorEnter();
void showDialog();
void hideDialog();
}
然后我們的實例就是Activity锦秒,使Acitivity繼承我們的接口湘纵,實現(xiàn)我們接口中的方法。
//申明persenter實例
LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
btn.setOnClickListener(this);
//通過Presenter實例類申明presenter
presenter = new LoginPresenterImpl(this);
}
@Override
public void loginSuccess() {
Toast.makeText(this,"登錄成功",Toast.LENGTH_SHORT).show();
}
@Override
public void ErrorPass() {
Toast.makeText(this,"密碼錯誤",Toast.LENGTH_SHORT).show();
}
@Override
public void ErrorEnter() {
Toast.makeText(this,"輸入錯誤",Toast.LENGTH_SHORT).show();
}
@Override
public void showDialog() {
loginProgress.setVisibility(View.VISIBLE);
}
@Override
public void hideDialog() {
loginProgress.setVisibility(View.GONE);
}
@Override
public void onClick(View v) {
User user = new User(name.getText().toString(), password.getText().toString());
//將檢驗事件回調(diào)給presenter砌左,讓他通知model進行檢驗
presenter.checkLogin(user);
}
}
Presenter層:
接下來是重點了汇歹,我們的Presenter類偿凭。
傳遞
作為view和model的中間傳達者。view告訴presenter需要檢驗了痰哨,然后presenter在告訴model,并把得到的user值給model斤斧,讓model進行檢驗。
申明presenter的接口類蕊连。
public interface LoginPresenter {
void checkLogin(User user);
}
接口實現(xiàn)類LoginPresenterImpl,我們在presenter的實例中游昼,獲取到view和model的實例,然后在里面對其進行信息傳遞载庭。
public class LoginPresenterImpl implements LoginPresenter,LoginModelListener{
LoginView view;
LoginModel model;
public LoginPresenterImpl(LoginView loginView){
//從Activity中獲取到對view的引用
this.view = loginView;
//申明一個新的model
model = new LoginModelImpl();
}
@Override
public void checkLogin(User user) {
//保證視圖是存在的
if (view == null){
return;
}
//顯示view中的dialog昧捷,然后對user信息進行驗證
view.showDialog();
model.login(user,this);
}
}
這樣我們就實現(xiàn)了將view的事件罐寨,通過presenter傳遞給了model層,讓他去處理這一次的檢驗事件跋破,但是大家有沒有發(fā)現(xiàn)瓶蝴,我們是將這個事件傳遞給了model,但是model在處理完了之后舷手,他又怎么將得到的結(jié)果通知給presenter呢男窟?因為我們要避免view和model直接接觸。所以在這里歉眷,我們還需要一個listenter的接口類汗捡,讓presenter繼承這個接口,在傳遞給model的時候,攜帶接口一起傳過去盗胀。然后model通過這個接口告訴presenter淡溯,presenter再去通知view。
public interface LoginModelListener {
void loginSuccess();
void loginError();
}
public interface LoginModel {
void login(User user, LoginModelListener listener);
}
public class LoginModelImpl implements LoginModel{
@Override
public void login(User user, final LoginModelListener listener) {
final String name = user.getName();
final String password = user.getPassword();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Boolean error =false;
if (TextUtils.isEmpty(name)){
error = true;
//輸入錯誤
System.out.println("輸入錯誤");
listener.loginError();
}
if (TextUtils.isEmpty(password)){
error = true;
//輸入錯誤
System.out.println("輸入錯誤");
listener.loginError();
}
if(!error){
//登錄成功
System.out.println("登錄成功");
listener.loginSuccess();
}
}
},2000);
}
}
至此强品,我們就實現(xiàn)了一個簡單的MVP的demo,是不是覺得Acitivity里面的邏輯很簡單了琼了,看著一下字就輕松了很多夫晌。
三、總結(jié)
那么我們現(xiàn)在結(jié)合剛才的案例所袁。我們再來總結(jié)一下凶掰。
因為我們要保證view和model直接不能直接通信,所有之間的交互懦窘,我們都要通過presenter這一個中間類來進行傳遞畅涂。persenter中擁有view和model的引用,然后午衰,view中有事件產(chǎn)生時苇经,將事件以及需要的參數(shù)傳給presenter,presenter再交給model扇单,待model處理完了之后,將反饋信息傳給presenter施流,presenter再將返回結(jié)果告訴view,最后呈現(xiàn)給用戶忿晕。