前言#
今天準備聊聊適配器模式舶治,適配器模式相比之前的觀察者模式或者是代理模式,我覺得思路的復(fù)雜度差不多搀暑,但是實現(xiàn)起來會稍微復(fù)雜一點。
適配器是什么呢跨琳?
很簡單,就以我現(xiàn)在身邊的東西:電腦的適配器桐罕,手機的適配器脉让,我們習(xí)慣的叫他們電源。
大家都知道實際上電壓都不是非常標準的220V功炮,因為要把電輸送到很遠的地方溅潜,發(fā)電站提供的電壓是非常高的,傳輸過程中還會損耗薪伏,所以我們平時使用的電壓都是經(jīng)過電壓的轉(zhuǎn)換的(例如變壓器)滚澜,有些對電壓要求比較高的設(shè)備,例如電腦嫁怀,手機设捐,他們的電源都會有簡單的電壓適配。
我們就是要把這個原理帶到程序中去塘淑。
正文#
說到Android的適配模式萝招,那肯定就是典型的ListView,RecyclerView的使用存捺,你只要實現(xiàn)最重要的幾個方法槐沼,保證轉(zhuǎn)換過程的執(zhí)行就OK了。如果你還沒弄清楚適配模式捌治,先繼承往下看岗钩。
那么我們就來模擬一下電源從傳輸?shù)绞褂玫倪^程,我先畫了一張原型圖:
里面的描述我們每一個環(huán)節(jié)需要實現(xiàn)的重要功能和作用肖油,這里就不再啰嗦了兼吓。但是從開發(fā)的角度還是要簡單分析一下:
1、適配器模式构韵,最好是以SDK開發(fā)的角度來分析周蹭,因為最終暴露給使用者的趋艘,只有基礎(chǔ)適配器和適配器的使用者。
2凶朗、當電壓發(fā)生了變化瓷胧,需要通知使用做相應(yīng)的調(diào)整,這里我們使用觀察者模式棚愤。
接下來我們按照原型圖搓萧,開始創(chuàng)建需要使用的類:
電壓提供者類和標準的電壓類:
/**
* Created by li.zhipeng on 2017/8/22.
* <p>
* 超高電壓類, 不能被耗電器直接使用
*/
public class Voltage1000 {
private int voltage;
public Voltage1000(int voltage){
this.voltage = voltage;
}
public int getVoltage(){
return this.voltage;
}
public void output() {
Log.e("lzp", "輸出了" + voltage + "V的電壓, 危險請勿直接使用");
}
}
/**
* Created by li.zhipeng on 2017/8/22.
* <p>
* 標準的電壓類,voltage可以隨意設(shè)置
*/
public class Voltage {
private int voltage;
public Voltage(int voltage) {
this.voltage = voltage;
}
public void output() {
Log.e("lzp", "輸出了" + voltage + "V的電壓宛畦,可以供家庭使用");
}
}
適配器接口類:
/**
* Created by li.zhipeng on 2017/8/22.
*
* 電壓的被觀察者瘸洛,用于通知電壓發(fā)生了變化
*/
public class VoltageObservable extends Observable {
/**
* 通知觀察者,已經(jīng)發(fā)生了變化
* */
public void notifyVoltageChanged(){
setChanged();
notifyObservers();
}
}
/**
* Created by li.zhipeng on 2017/8/22.
* <p>
* 這是電壓的基本接口
*/
public interface VoltageImpl {
/**
* 輸出電壓次和,負責轉(zhuǎn)換的過程
*/
Voltage convertVoltage(Voltage1000 voltage);
}
基礎(chǔ)的電壓適配器:
/**
* Created by li.zhipeng on 2017/8/22.
*
* 電壓的基礎(chǔ)適配器
*/
public abstract class BaseVoltageAdapter implements VoltageImpl {
/**
*
* 要輸出的電壓
*/
private int voltage;
/**
* 通知的回調(diào)反肋,這里可以使用觀察者模式,模仿BaseAdapter
* */
private VoltageObservable observable;
/**
* 獲取當前的電壓
* */
public int getVoltage() {
return voltage;
}
/**
* 設(shè)置電壓
* */
public void setVoltage(int voltage) {
this.voltage = voltage;
}
/**
* 構(gòu)造方法
* */
public BaseVoltageAdapter(int voltage){
this.voltage = voltage;
observable = new VoltageObservable();
}
/**
* 當電壓發(fā)生了變化踏施,通知使用者
* */
public void notifiVoltageChanged(){
observable.notifyVoltageChanged();
}
/**
* 獲取被觀察者
* */
public VoltageObservable getVoltageObservable(){
return this.observable;
}
}
耗電器類:
/**
* Created by li.zhipeng on 2017/8/22.
* <p>
* 耗電設(shè)備類
*/
public class VoltageMachine {
/**
* 初始電壓
*/
private Voltage1000 voltage1000;
/**
* 要輸出電壓的次數(shù)
*/
private int outputCount;
/**
* 電壓的適配器
*/
private BaseVoltageAdapter baseVoltageAdapter;
/**
* 構(gòu)造方法
* */
public VoltageMachine(Voltage1000 voltage1000, int outputCount){
this.voltage1000 = voltage1000;
this.outputCount = outputCount;
}
/**
* 循環(huán)輸出電壓
*/
public void outputVotalge() {
for (int i = 0; i < outputCount; i++) {
Voltage voltage = baseVoltageAdapter.convertVoltage(voltage1000);
voltage.output();
}
}
/**
* 設(shè)置適配器
*/
public BaseVoltageAdapter getAdapter() {
return baseVoltageAdapter;
}
/**
* 獲取適配器
*/
public void setAdapter(BaseVoltageAdapter baseVoltageAdapter) {
// 先解綁之前的的被觀察者
unregisterVoltageObserable();
// 設(shè)置適配器
this.baseVoltageAdapter = baseVoltageAdapter;
// 注冊新的被觀察者
registerVoltageObserable();
// 開始輸出電壓
outputVotalge();
}
/**
* 獲取輸出次數(shù)
*/
public int getOutputCount() {
return outputCount;
}
/**
* 設(shè)置輸出次數(shù)
*/
public void setOutputCount(int outputCount) {
this.outputCount = outputCount;
}
/**
* 定義當電壓發(fā)生變化的
*/
private Observer observer = new Observer() {
@Override
public void update(Observable o, Object arg) {
outputVotalge();
}
};
/**
* 注冊適配器的觀察者
*/
private void registerVoltageObserable() {
if (baseVoltageAdapter != null) {
baseVoltageAdapter.getVoltageObservable().addObserver(observer);
}
}
/**
* 解綁適配器的觀察者
*/
private void unregisterVoltageObserable() {
if (baseVoltageAdapter != null) {
baseVoltageAdapter.getVoltageObservable().deleteObserver(observer);
}
}
}
基礎(chǔ)的類我們已經(jīng)都貼出來了石蔗,主要有以下幾點需要注意以下:
1、在setAdapter時畅形,要保證只注冊了一個被觀察者养距,否則可能會發(fā)生無用的更新,甚至程序運行的異常日熬。
2棍厌、當耗電器使用結(jié)束,setAdapter(null)竖席,解除耦合耘纱,并且解綁被觀察者。真正的開發(fā)中怕敬,防止內(nèi)存泄漏這里要尤其注意揣炕。
3、個別方法使用了private东跪,注意sdk開發(fā)時有些方法不要開放畸陡,這個尺度根據(jù)自己的需求來權(quán)衡。
ok虽填,現(xiàn)在終于到了應(yīng)用層的開發(fā)丁恭,這個就簡單多了:
為了讓打印結(jié)果好區(qū)分,我簡單的重寫了output方法斋日,增加一條分隔線
/**
* Created by li.zhipeng on 2017/8/22.
*
* 這是一個大型的耗電機器
*/
public class LargePowerMachine extends VoltageMachine{
/**
* 構(gòu)造方法
*
* @param voltage1000
* @param outputCount
*/
public LargePowerMachine(Voltage1000 voltage1000, int outputCount) {
super(voltage1000, outputCount);
}
/**
* 自定義輸出的邏輯
* */
@Override
public void outputVotalge() {
super.outputVotalge();
// 輸出結(jié)束的時候牲览,再輸出一條分界線
Log.e("lzp", "-------------------");
}
}
實現(xiàn)自定義的適配器:
/**
* Created by li.zhipeng on 2017/8/22.
*
* 自定義適配器類
*/
public class MyVoltageAdapter extends BaseVoltageAdapter {
/**
* 構(gòu)造方法
*
* @param voltage
*/
public MyVoltageAdapter(int voltage) {
super(voltage);
}
/**
* 重寫電壓的轉(zhuǎn)換方法
* */
@Override
public Voltage convertVoltage(Voltage1000 voltage) {
// 這里進行了電壓之間的轉(zhuǎn)換
// 假設(shè)這里有很多很復(fù)雜的操作
// 我這里啥也沒寫
return new Voltage(getVoltage());
}
}
最后是MainActivity的代碼:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 創(chuàng)建一個耗電器, 初始電壓是1000,需要輸出5次電壓
LargePowerMachine largePowerMachine = new LargePowerMachine(new Voltage1000(1000), 5);
// 添加一個適配器,這里我們需要220V的電壓
final MyVoltageAdapter myVoltageAdapter = new MyVoltageAdapter(220);
largePowerMachine.setAdapter(myVoltageAdapter);
//
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 需求發(fā)生變化,這里突然要輸出100V的電壓
myVoltageAdapter.setVoltage(110);
myVoltageAdapter.notifiVoltageChanged();
}
});
}
}
輸出結(jié)果:
<h2>探討適配器模式的使用場景</h2>
經(jīng)過一個小demo恶守,我們對適配器的理解又提升了一個檔次第献,首先我們對他進行一個綜合評價:
1贡必、開發(fā)的成本比較高,為了完成適配模式庸毫,我們定義了比較多的類仔拟。
2、可以通過泛型適當?shù)妮^少適配器工作量飒赃。
3利花、適配器模式只關(guān)心轉(zhuǎn)換結(jié)果,不關(guān)心轉(zhuǎn)換過程载佳,處于整個使用過程的中間炒事。
那么他應(yīng)該在什么樣的場景使用呢?我個人有以下幾種理解:
1蔫慧、轉(zhuǎn)換源和轉(zhuǎn)換結(jié)果的類型長期穩(wěn)定挠乳,不能發(fā)生大的變動,通過適配器模式藕漱,為提供者提供不同的解決方案欲侮。
2、對于轉(zhuǎn)換的結(jié)果比較敏感肋联,當結(jié)果發(fā)生改變時,要及時的應(yīng)對刁俭。
3橄仍、只關(guān)心轉(zhuǎn)換的結(jié)果,不關(guān)心來源和如何使用牍戚。
要說平時到底哪里用的多侮繁,我現(xiàn)在只能想起來模塊開發(fā),其實模塊開發(fā)也是SDK開發(fā)的一種如孝,只負責提供服務(wù)宪哩,具體要什么樣的結(jié)果,讓使用者自己來定義第晰,例如我提供的User信息锁孟,你想要怎么處理User都可以,與我無關(guān)茁瘦。
總之品抽,當你要開發(fā)一個穩(wěn)定的模塊,并且要為其他人提供相同類型的服務(wù)甜熔,我希望你能夠先思考適配模式圆恤。
總結(jié)#
適配模式就是這樣了,應(yīng)用開發(fā)這個模式我確實用的不多腔稀,如果有一天你要開發(fā)SDK了盆昙,千萬別忘了他羽历。