禮拜5下午,有一些小夥伴在討論關於“我對MVP的理解啊”,“我對RxJava,RxAndroid的理解啊”等等。在交流中發現,其實我們往往在實際開發中有意無意的都可能出現某個類特別的繁雜,程式碼特別的多,而且其實很多都是重複的,但是又沒有辦法,諸如一大堆回撥。
可能在專案構建之初,想著我要如何如何去實現,如何如何優化程式碼結構,邏輯等等,可是因為理解或者業務繁重等各個因素,導致到後來還是擠成一坨龍貓,像這樣(麥麥胖的腳都看不見了,臃腫,不過可愛!!)
這裡不說RxJava的那些內容就簡單的從MVP再來解釋一遍,理解一遍,什麼是抽象類,什麼是介面。
很多人其實對抽象類和介面覺得他們都差不多,他們都不是實體類,他們都可以被實現,都可以被繼承,那麼區別又在哪?
我記得以前在一開始進入軟體行業的時候,面試官都問的很基礎最突出的是以下幾個問題
1.什麼是抽象類,什麼是介面,他們的區別是什麼?
2.什麼是ArrayList,什麼是LinkedList,他們的區別是什麼?
3.什麼是HashMap,什麼是Hashtable,他們的區別是什麼?
相信大家對著3個問題一定記憶猶新,都快成了java程式設計師面試的必考題了。
這裡只解釋第一個問題
抽象類:
在OOP中,萬物皆物件(這句話印象深刻),同時所有的物件都是通過類來描述的,但是並不是所有的類都是來描述物件的。如果一個類沒有足夠的資訊來描述一個具體的物件,而需要其他具體的類來支撐它,那麼這樣的類我們稱它為抽象類。
介面:
介面是一種比抽象類更加抽象的“類”。介面是用來建立類與類之間的協議,它所提供的只是一種形式,而沒有具體的實現,介面是抽象類的延伸。
區別:
網上有一大堆說區別啊,概念的,這些都比較具體,但是我認為,最確切,最重要的一點是 “抽象類是對類抽象,而介面是對行為的抽象。”
Ok,理解了嗎?不理解?那我們來看今天的例子,這個例子是上次MVP Demo的延伸,先看一下執行的效果。
這邊就是一個簡單的例子,邏輯大致如此:
我們有一個EditText,有一個Button,當Button被點選的時候獲取EditText的文字內容做一個判斷,大於5顯示一些字,小於5顯示一些字,根據判斷的結果,列印依據Log,Log如下:
我們再來貼下包目錄,這次請仔細看結構,因為這也是講解的一部分:
我們現在所看到的這個類是MainActivity這個類,BaseActivity是他的父類,LoginActivity是之前的例子,想了解的可以看:http://blog.csdn.net/ddwhan0123/article/details/51009279
我們還有一個Common目錄,裡面有一個介面,DialogInterface看名字就知道是跟Dialog相關的一個介面(取名規範不規範我們另議,大家理解他幹嘛的比較重要)
Login目錄無視
Main目錄下有1個類和2個介面。
MainResult這個介面是用於輸入內容判斷所用的介面。
MainButtonClick這個介面是使用者點選按鈕所觸發的一些行為所用的介面。
MainCLickImp這個類用於實現之前的介面。
從頭開始看,我們先看父類BaseActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayout()); findId(); logic(); } abstract void findId(); abstract int getLayout(); abstract void logic(); protected void showToast(Context context, String msg) { Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } } |
我們的BaseActivity是一個抽象類,他有3個抽象方法供子類實現,分別是findId(),getLayout(),logic() 看名字我們就理解,分別是 用於獲取控制元件物件,用於獲取佈局ID,用於邏輯處理。
BaseActivity有一個帶protected的方法showToast(Context context, String msg)
,一目瞭然,這是給與子類呼叫的。
為什麼這裡用一個抽象類去做這些事情,也可以寫個介面來做,像這樣
1 2 3 4 5 6 7 8 |
//沒想到什麼好名字,你理解就好 public interface BaseXXXXX{ abstract void findId(); abstract int getLayout(); abstract void logic(); } |
我們之前所說的 物件都是通過類來描述的。因為我們接下來的那些子類可能都有初始化的操作,可能都要獲取佈局,可能都要有簡單的邏輯。這些行為都是這個類本身就應該具有的,只是可能具體的行為我們描述不清,所以我們用一個抽象類來描述這麼個“不具體”的物件(所以,繼承了他的子類一定是具體的)這裡再提一提 抽象類是對類抽象,這麼看來沒錯吧,父類描述了個大題的樣子,讓具體的子類去實現。
接下來我們再來看下DialogInterface這個介面
1 2 3 4 5 6 7 8 |
/** * 介面是對行為的抽象,作用於模擬進度條 **/ public interface DialogInterface { void show(); void hide(); } |
這個介面有2個方法,一個用來模擬showDialog,那另外個就是hideDialog了。
那麼為什麼,沒有把這2個方法放到我們的BaseActivity中呢?
不是所有的子類都需要Dialog,那麼相關於Dialog的行為並不是這些Activity所固有的,所以我們用一個介面來給需要Dialog行為的子類來實現!因為介面是對行為的抽象,介面跟實現類本身不存在概念本質上的一致,而抽象類必須是
上面2者的關係解釋完,後面的東西就好理解了
MainButtonClick只負責使用者點選行為的傳遞,而它本身不在意他做了什麼
1 2 3 4 5 6 7 |
public interface MainButtonClick { //按鈕的行為,傳入作為比較用的介面 MainResult,並把判斷的結果返回 boolean MainButtonClickListener(int value, MainResult mainResult); //根據判斷的結果決定是否顯示Dialog,傳入作為dialog的介面 DialogInterface void ShowDialog(boolean value, DialogInterface dialogInterface); } |
MainResult只負責使用者結果的比對,而它本身不在意他做了什麼
1 2 3 4 5 |
public interface MainResult { void Greater(); void Less(); } |
OK,再之後就是我們最在意的2個實體類,先從“衝做 MVP模式裡”Presenter的MainClickImp說起。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class MainClickImp implements MainButtonClick { @Override public boolean MainButtonClickListener(int value, MainResult mainResult) { if (value > 5) { mainResult.Greater(); return true; } else { mainResult.Less(); return false; } } @Override public void ShowDialog(boolean value, DialogInterface dialogInterface) { if (value) { dialogInterface.show(); } else { dialogInterface.hide(); } } } |
MainClickImp實現了我們使用者點選的實現,同時我們的業務流程全部都在這裡完成。因為我們的MainActivity這個類是有Dialog行為的所以我把點選事件引發的Dialog行為也放到實現類裡一起實現。
最後我們來看下我們原本可能相對比較繁雜的MainActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
public class MainActivity extends BaseActivity implements MainResult, DialogInterface, View.OnClickListener { EditText edit; Button button; Toolbar toolbar; MainButtonClick mainButtonClick; @Override void findId() { toolbar = (Toolbar) findViewById(R.id.toolbar); edit = (EditText) findViewById(R.id.edit); button = (Button) findViewById(R.id.button); } @Override int getLayout() { return R.layout.activity_main; } @Override void logic() { StatusBarUtil.setColor(this, getResources().getColor(R.color.colorAccent), 0); setSupportActionBar(toolbar); button.setOnClickListener(this); mainButtonClick = new MainClickImp(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public static void LogicSuccess(Activity activity) { Intent intent = new Intent(activity, MainActivity.class); activity.startActivity(intent); } @Override public void Greater() { showToast(this, "大於5"); } @Override public void Less() { showToast(this, "小於5"); } @Override public void show() { LogUtils.d("--->show"); } @Override public void hide() { LogUtils.d("--->hide"); } @Override public void onClick(View v) { if (v.getId() == R.id.button) { int value = Integer.parseInt(edit.getText().toString().trim()); //沒寫值空不空的判斷了,別沒事找事了,隨便填數字就行!!! boolean flag = mainButtonClick.MainButtonClickListener(value, MainActivity.this); mainButtonClick.ShowDialog(flag, MainActivity.this); } } } |
我們發現,我們的Activity實現了父類的3個初始化方法,點選行為引發的判斷方法以及Dialog方法。
此時觀眾朋友們肯定會心存疑慮,我們整了那麼多介面啊,實現類啊怎麼程式碼沒有想象中的少,感覺還多了?
這邊來解釋,首先你的程式碼邏輯變得更清晰,點選發起點 找
onClick(View v)
Dialog顯示找
1 |
show() |
Dialog消失找
1 |
hide() |
大於預設值找
1 |
Greater() |
小於預設值找
1 |
Less() |
我們的程式碼不再是在 onCreate()裡有“一卡車程式碼”,就算要再加功能,加邏輯只要新增介面,實現業務邏輯就行,我們的Activity更純粹,更乾淨。
下面給基礎差的小夥伴們講解下:
因為介面是不可以new的所以我們要跑介面中的方法怎麼辦?
例子中,我new 了一個實現類的例項,雖然呼叫的時候還是mainButtonClick.MainButtonClickListener(value, MainActivity.this);
但是這些事情都是讓MainClickImp去做了
這裡我們把MainActivity.this自己傳入了MainClickImp並不是作為Context之類的需要,而是因為我們的MainActivity實現了MainResult, DialogInterface
,我們才能在Activity這裡享受到MainClickImp裡執行的邏輯。
簡單的說他就是形成了一個環
1.Activity的呼叫
2.MainClickImp去實現邏輯
3.又因為Activity參與了實現過程,所以在Activity裡的方法才能被執行,不然就是 null Object。
好累,一不小心又禮拜6下午了。。。週末還沒休息。。。。大家週末愉快
因為這臺電腦沒有git相關環境,就不丟git了。。CSDN下載地址吧,禮拜1再丟git
原始碼地址:http://download.csdn.net/detail/ddwhan0123/9493126
這裡再安利下,我的整合庫,讓大家找資源更方便,謝謝支援:http://blog.csdn.net/ddwhan0123/article/details/51145547
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!