前言
Android的設計模式系列文章介紹,歡迎關注,持續更新中:
Android的設計模式-設計模式的六大原則
一句話總結23種設計模式則
創建型模式:
Android的設計模式-單例模式
Android的設計模式-建造者模式
Android的設計模式-工廠方法模式
Android的設計模式-簡單工廠模式
Android的設計模式-抽象工廠模式
Android的設計模式-原型模式
行為型模式:
Android的設計模式-策略模式
Android的設計模式-狀態模式
Android的設計模式-責任鏈模式
Android的設計模式-觀察者模式
Android的設計模式-模板方法模式
Android的設計模式-迭代器模式
Android的設計模式-備忘錄模式
Android的設計模式-訪問者模式
Android的設計模式-中介者模式
Android的設計模式-解釋器模式
Android的設計模式-命令模式
結構型模式:
Android的設計模式-代理模式
Android的設計模式-組合模式
Android的設計模式-適配器模式
Android的設計模式-裝飾者模式
Android的設計模式-享元模式
Android的設計模式-外觀模式
Android的設計模式-橋接模式
1.定義
動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
2.介紹
- 裝飾者模式屬于結構型模式。
- 裝飾者模式在生活中應用實際上也非常廣泛,一如一間房,放上廚具,它就是廚房;放上床,就是臥室。
- 通常我們擴展類的功能是通過繼承的方式來實現,但是裝飾者模式是通過組合的方式來實現,這是繼承的替代方案之一。
3.UML類圖
角色說明:
- Component(抽象組件):接口或者抽象類,被裝飾的最原始的對象。具體組件與抽象裝飾角色的父類。
- ConcreteComponent(具體組件):實現抽象組件的接口。
- Decorator(抽象裝飾角色):一般是抽象類,抽象組件的子類,同時持有一個被裝飾者的引用,用來調用被裝飾者的方法;同時可以給被裝飾者增加新的職責。
- ConcreteDecorator(具體裝飾類):抽象裝飾角色的具體實現。
4.實現
就以裝修房間為例子
4.1 創建抽象組件
這里是一個抽象房子類,定義一個裝修的方法:
public abstract class Room {
public abstract void fitment();//裝修方法
}
4.2 創建具體組件
現在有一間新房子,已經裝上了電:
public class NewRoom extends Room {//繼承Room
@Override
public void fitment() {
System.out.println("這是一間新房:裝上電");
}
}
4.3 創建抽象裝飾角色
要為房子裝修,定義抽象的房間裝飾類:
public abstract class RoomDecorator extends Room {//繼承Room,擁有父類相同的方法
private Room mRoom;//持有被裝飾者的引用,這里是需要裝修的房間
public RoomDecorator(Room room) {
this.mRoom = room;
}
@Override
public void fitment() {
mRoom.fitment();//調用被裝飾者的方法
}
}
4.4 創建具體裝飾類
我們要將房間裝修成臥室和廚房,其具體實現是不同的:
public class Bedroom extends RoomDecorator {//臥室類,繼承自RoomDecorator
public Bedroom(Room room) {
super(room);
}
@Override
public void fitment() {
super.fitment();
addBedding();
}
private void addBedding() {
System.out.println("裝修成臥室:添加臥具");
}
}
public class Kitchen extends RoomDecorator {//廚房類,繼承自RoomDecorator
public Kitchen(Room room) {
super(room);
}
@Override
public void fitment() {
super.fitment();
addKitchenware();
}
private void addKitchenware() {
System.out.println("裝修成廚房:添加廚具");
}
}
4.5 客戶端測試:
public void test() {
Room newRoom = new NewRoom();//有一間新房間
RoomDecorator bedroom = new Bedroom(newRoom);
bedroom.fitment();//裝修成臥室
RoomDecorator kitchen = new Kitchen(newRoom);
kitchen.fitment();//裝修成廚房
}
輸出結果:
這是一間新房:裝上電
裝修成臥室:添加臥具
這是一間新房:裝上電
裝修成廚房:添加廚具
5. 應用場景
- 需要擴展一個類的功能,或給一個類增加附加功能時
- 需要動態的給一個對象增加功能,這些功能可以再動態的撤銷
- 當不能采用繼承的方式對系統進行擴充或者采用繼承不利于系統擴展和維護時。
6. 優點
- 采用組合的方式,可以動態的擴展功能,同時也可以在運行時選擇不同的裝飾器,來實現不同的功能。
- 有效避免了使用繼承的方式擴展對象功能而帶來的靈活性差,子類無限制擴張的問題。
- 被裝飾者與裝飾者解偶,被裝飾者可以不知道裝飾者的存在,同時新增功能時原有代碼也無需改變,符合開放封閉原則。
7. 缺點
- 裝飾層過多的話,維護起來比較困難。
- 如果要修改抽象組件這個基類的話,后面的一些子類可能也需跟著修改,較容易出錯。
8. Android中的源碼分析
我們都知道Activity
、Service
、Application
等都是一個Context
,這里面實際上就是通過裝飾者模式來實現的。下面以startActivity()
這個方法來簡單分析一下。
8.1 Context類
Context
實際上是個抽象類,里面定義了大量的抽象方法,其中就包含了startActivity()
方法:
public abstract class Context {//抽象類
public abstract void startActivity(@RequiresPermission Intent intent);//抽象方法
//其他代碼略
}
8.2 ContextImpl類
Context
類的具體實現實際上是在ContextImpl
類,里面具體實現了startActivity()
方法:
class ContextImpl extends Context {
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, Bundle options) {//具體實現原理這里就不分析了
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
//其他代碼略
}
8.3 ContextWrapper類
通常我們在Activity
、Service
里面調用startActivity()
方法,實際上是調用他們的父類ContextWrapper
里面的startActivity()
方法,我們先來看下Activity
、Service
的繼承關系:
可以看到Activity
、Service
都是繼承自ContextWrapper
,再來看看ContextWrapper
的代碼:
public class ContextWrapper extends Context {//Context包裝類
Context mBase;//持有Context引用
public ContextWrapper(Context base) {//這里的base實際上就是ContextImpl
mBase = base;
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);//調用ContextImpl的startActivity()方法
}
//其他代碼略
}
8.4 總結
Context
類在這里就充當了抽象組件的角色,ContextImpl
類則是具體的組件,而ContextWrapper
就是具體的裝飾角色,通過擴展ContextWrapper
增加不同的功能,就形成了Activity
、Service
等子類。最后,放一張總的UML類圖幫助理解:
相關文章閱讀
Android的設計模式-設計模式的六大原則
一句話總結23種設計模式則
創建型模式:
Android的設計模式-單例模式
Android的設計模式-建造者模式
Android的設計模式-工廠方法模式
Android的設計模式-簡單工廠模式
Android的設計模式-抽象工廠模式
Android的設計模式-原型模式
行為型模式:
Android的設計模式-策略模式
Android的設計模式-狀態模式
Android的設計模式-責任鏈模式
Android的設計模式-觀察者模式
Android的設計模式-模板方法模式
Android的設計模式-迭代器模式
Android的設計模式-備忘錄模式
Android的設計模式-訪問者模式
Android的設計模式-中介者模式
Android的設計模式-解釋器模式
Android的設計模式-命令模式
結構型模式:
Android的設計模式-代理模式
Android的設計模式-組合模式
Android的設計模式-適配器模式
Android的設計模式-裝飾者模式
Android的設計模式-享元模式
Android的設計模式-外觀模式
Android的設計模式-橋接模式