前言
Android的設(shè)計(jì)模式系列文章介紹,歡迎關(guān)注,持續(xù)更新中:
Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式
1.定義
將一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作杆勇。
2.介紹
- 適配器模式屬于結(jié)構(gòu)型模式。
- 適配器模式有類適配器模式和對象適配器模式這兩種。
- 生活中的手機(jī)充電器就是一個適配器的例子趟畏,手機(jī)一般都是在5V的電壓下進(jìn)行充電,但是外部的電壓都是220V滩租,那怎么辦赋秀,這就需要充電器去適配了,將220V的電壓轉(zhuǎn)換為5V持际。
- 實(shí)際開發(fā)中沃琅,我們常遇到兩個類之間的接口不兼容,但是又不想去改動接口蜘欲,這可以通過適配器模式來解決這個問題益眉。
-
放張比較形象的圖:
適配器示例.png
3.UML類圖
角色說明:
- Adapter(適配器接口):即目標(biāo)角色,定義把其他類轉(zhuǎn)換為何種接口姥份,也就是我們期望的接口郭脂。
- Adaptee(被適配角色):即源角色,一般是已存在的類澈歉,需要適配新的接口展鸡。
- ConcreteAdapter(具體適配器):實(shí)現(xiàn)適配器接口,把源角色接口轉(zhuǎn)換為目標(biāo)角色期望的接口埃难。
4.對象適配器模式實(shí)現(xiàn)
首先來說下對象適配器模式的實(shí)現(xiàn)方式莹弊,就以電壓轉(zhuǎn)換為例子。
4.1 創(chuàng)建適配器接口
現(xiàn)在我們需要定義一個220V轉(zhuǎn)換成5V的接口:
interface Adapter {//適配器類
int convert_5v();//裝換成5V
}
4.2 創(chuàng)建被適配角色
被適配角色涡尘,一般是已存在的類忍弛,需要適配新的接口。生活中的220V電源無處不在:
public class Electric {// 電源
public int output_220v() {//輸出220V
return 220;
}
}
4.3 創(chuàng)建具體適配器
我們需要一個具體適配器考抄,這個適配器就是變壓器细疚,能夠?qū)?20V轉(zhuǎn)為5V輸出:
public class PhoneAdapter implements Adapter {//手機(jī)適配器類
private Electric mElectric;//適配器持有源目標(biāo)對象
public PhoneAdapter(Electric electric) {//通過構(gòu)造方法傳入對象
mElectric = electric;
}
@Override
public int convert_5v() {
System.out.println("適配器開始工作:");
System.out.println("輸入電壓:" + mElectric.output_220v());
System.out.println("輸出電壓:" + 5);
return 5;
}
}
4.4 客戶端測試:
public void test() {
Electric electric = new Electric();
System.out.println("默認(rèn)電壓:" + electric.output_220v());
Adapter phoneAdapter = new PhoneAdapter(electric);//傳遞一個對象給適配器
System.out.println("適配轉(zhuǎn)換后的電壓:" + phoneAdapter.convert_5v());
}
輸出結(jié)果:
默認(rèn)電壓:220
適配器開始工作:
輸入電壓:220
輸出電壓:5
適配轉(zhuǎn)換后的電壓:5
4.5 說明:
上面的例子就是對象適配器模式,適配的源目標(biāo)對象需要傳遞給適配器川梅。
5.類適配器模式實(shí)現(xiàn)
類適配器只要是通過繼承源目標(biāo)類來實(shí)現(xiàn)
5.1 創(chuàng)建適配器接口
跟4.1一樣
interface Adapter {//適配器類
int convert_5v();//裝換成5V
}
5.2 創(chuàng)建被適配角色
跟4.2一樣
public class Electric {// 電源
public int output_220v() {//輸出220V
return 220;
}
}
5.3 創(chuàng)建具體適配器
跟4.3有區(qū)別
public class PhoneAdapter extends Electric implements Adapter {//通過繼承源目標(biāo)類的方式疯兼,不持有源目標(biāo)對象
@Override
public int convert_5v() {
System.out.println("適配器開始工作:");
System.out.println("輸入電壓:" + output_220v());
System.out.println("輸出電壓:" + 5);
return 5;
}
}
5.4 客戶端測試:
跟4.4有區(qū)別
public void test() {
Adapter phoneAdapter = new PhoneAdapter();
System.out.println("適配轉(zhuǎn)換后的電壓:" + phoneAdapter.convert_5v());
}
輸出結(jié)果:
適配器開始工作:
輸入電壓:220
輸出電壓:5
適配轉(zhuǎn)換后的電壓:5
5.5 說明:
類適配器模式只要通過繼承源目標(biāo)類來實(shí)現(xiàn),無需持有源目標(biāo)對象贫途。
5.6 對象適配器模式與類適配器模式比較
- 類適配器采用了繼承的方式來實(shí)現(xiàn);而對象適配器是通過傳遞對象來實(shí)現(xiàn)吧彪,這是一種組合的方式。
- 類適配器由于采用了繼承丢早,可以重寫父類的方法;對象適配器則不能修改對象本身的方法等姨裸。
- 適配器通過繼承都獲得了父類的方法,客戶端使用時都會把這些方法暴露出去,增加了一定的使用成本;對象適配器則不會啦扬。
- 類適配器只能適配他的父類中狂,這個父類的其他子類都不能適配到;而對象適配器可以適配不同的對象,只要這個對象的類型是同樣的扑毡。
- 類適配器不需要額外的引用;對象適配器需要額外的引用來保存對象胃榕。
總的來說,使用對象適配器比較好瞄摊。當(dāng)然具體問題具體分析勋又。
6. 應(yīng)用場景
- 當(dāng)想使用一個已經(jīng)存在的類,但它的接口不符合需求時换帜。
- 當(dāng)想創(chuàng)建一個可以復(fù)用的類楔壤,該類可以與其他不相關(guān)的類或不可預(yù)見的類協(xié)同工作。
7. 優(yōu)點(diǎn)
- 提高了類的復(fù)用性惯驼,適配器能讓一個類有更廣泛的用途蹲嚣。
- 提高了靈活性,更換適配器就能達(dá)到不同的效果祟牲。不用時也可以隨時刪掉適配器隙畜,對原系統(tǒng)沒影響。
- 符合開放封閉原則说贝,不用修改原有代碼议惰。沒有任何關(guān)系的類通過增加適配器就能聯(lián)系在一起。
8. 缺點(diǎn)
- 過多的使用適配器乡恕,會讓系統(tǒng)非常零亂言询,不易整體進(jìn)行把握。明明調(diào)用A接口傲宜,卻被適配成B接口运杭。
9. Android中的源碼分析
說到適配器,ListView
和RecyclerView
就再熟悉不過了蛋哭,ListView
現(xiàn)在應(yīng)該很少用了吧县习,這里就以RecyclerView
來分析涮母。
9.1 RecyclerView的使用
先來一個RecyclerView
的簡單使用例子:
Activity布局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_main_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
</LinearLayout>
Item 布局文件 item_rv.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:id="@+id/tv_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:text="item"/>
</LinearLayout>
Activity代碼
public class MainActivity extends Activity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVar();
initView();
}
private void initVar() {
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mAdapter = new MyAdapter(getData());
}
private void initView() {
mRecyclerView = findViewById(R.id.rv_main_test);
// 設(shè)置布局管理器
mRecyclerView.setLayoutManager(mLayoutManager);
// 設(shè)置adapter
mRecyclerView.setAdapter(mAdapter);
}
private ArrayList<String> getData() {//獲取要展示的數(shù)據(jù)
ArrayList<String> data = new ArrayList<>();
String temp = " item";
for (int i = 0; i < 20; i++) {
data.add(i + temp);
}
return data;
}
}
Adapter代碼
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {//繼承RecyclerView.Adapter
private ArrayList<String> mData;
public MyAdapter(ArrayList<String> data) {
this.mData = data;//初始化數(shù)據(jù)
}
@Override
//創(chuàng)建一個我們自定義的ViewHolder
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 實(shí)例化要展示的view布局
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv, parent, false);
// 實(shí)例化viewholder
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
//綁定ViewHolder
public void onBindViewHolder(ViewHolder holder, int position) {
// ViewHolder中的view與數(shù)據(jù)進(jìn)行綁定
holder.mTv.setText(mData.get(position));
}
@Override
//Item數(shù)量
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView mTv;
public ViewHolder(View itemView) {//根據(jù)實(shí)際需求谆趾,持有不同的對象。
super(itemView);
mTv = itemView.findViewById(R.id.tv_item);
}
}
}
從上面的例子可以看到叛本,使用RecyclerView
時我們要傳遞一個Adapter
進(jìn)去沪蓬,然后通過復(fù)寫Adapter
中的onCreateViewHolder()
、onBindViewHolder()
来候、getItemCount()
等方法以及內(nèi)部類ViewHolder
跷叉。通過不同的Adapter
,我們能夠?qū)崿F(xiàn)不同的布局。
9.2 總結(jié)
上面的MyAdapter
是繼承RecyclerView.Adapter
這個類的云挟,而Adapter
實(shí)際上是RecyclerView
的內(nèi)部類梆砸。這里的Adapter
就充當(dāng)了適配器接口,即目標(biāo)角色园欣,RecyclerView
內(nèi)部通過Adapter
獲取它需要的接口和數(shù)據(jù)等帖世。至于MyAdapter
,就是具體的適配器沸枯,通過它把不同的布局跟RecyclerView
聯(lián)系起來日矫。最后就是被適配角色,即源角色绑榴,這里就是各種不同的item布局哪轿。
為什么Android要這么設(shè)計(jì)呢,想想在一個列表中翔怎,我們要展示的布局可能是簡單的窃诉,也可能是超復(fù)雜的,這個布局是未知的,是根據(jù)要展示的數(shù)據(jù)集來決定的;通過適配器模式赤套,就能夠把不同的東西都可以轉(zhuǎn)化成同樣的接口褐奴,系統(tǒng)處理起來就有套路了,同時也無需關(guān)心各種千變?nèi)f化的布局于毙。
相關(guān)文章閱讀
Android的設(shè)計(jì)模式-設(shè)計(jì)模式的六大原則
一句話總結(jié)23種設(shè)計(jì)模式則
創(chuàng)建型模式:
Android的設(shè)計(jì)模式-單例模式
Android的設(shè)計(jì)模式-建造者模式
Android的設(shè)計(jì)模式-工廠方法模式
Android的設(shè)計(jì)模式-簡單工廠模式
Android的設(shè)計(jì)模式-抽象工廠模式
Android的設(shè)計(jì)模式-原型模式
行為型模式:
Android的設(shè)計(jì)模式-策略模式
Android的設(shè)計(jì)模式-狀態(tài)模式
Android的設(shè)計(jì)模式-責(zé)任鏈模式
Android的設(shè)計(jì)模式-觀察者模式
Android的設(shè)計(jì)模式-模板方法模式
Android的設(shè)計(jì)模式-迭代器模式
Android的設(shè)計(jì)模式-備忘錄模式
Android的設(shè)計(jì)模式-訪問者模式
Android的設(shè)計(jì)模式-中介者模式
Android的設(shè)計(jì)模式-解釋器模式
Android的設(shè)計(jì)模式-命令模式
結(jié)構(gòu)型模式:
Android的設(shè)計(jì)模式-代理模式
Android的設(shè)計(jì)模式-組合模式
Android的設(shè)計(jì)模式-適配器模式
Android的設(shè)計(jì)模式-裝飾者模式
Android的設(shè)計(jì)模式-享元模式
Android的設(shè)計(jì)模式-外觀模式
Android的設(shè)計(jì)模式-橋接模式