Overview of Content
如有引用參考請詳註出處,感謝
本文介紹了建構者模式在 Android Framework 中對話框視窗的應用
首先,我們會探討建構者模式的使用場景,並介紹建構者模式的定義和 UML 圖。接著,我們會討論建構者模式的設計,包括其優缺點以及不同的實現方式。
在具體實現部分我們會深入分析 Android Framework 中對話框視窗的原始碼,包括基礎使用方法、AlertDialog 的建構者模式變型,以及對話框顯示畫面的實現過程。
透過本文,讀者將了解建構者模式在 Android 開發中的應用,並學會如何運用這一設計模式來提高程式碼的可讀性和可維護性。
Builder 使用場景
該模式是為了將 複雜物件的建構解偶,部件 & 組裝分離
● Builder 可進行客制化物件的建構,使其產生更細緻的不同物件(由 Builder
模式的使用者設定物件細節)
● Builder 的設計可以使的相同方法,不同執行順序,產生不同的結果
● 當初始化一個物件很複雜(建構子需要的元素過多),且參數都有預設值
● Factory vs. Builder
兩者的相同點都在於產生一個產品給使用者用,但 兩者關注重點不同!
● Factory 則關注產品的生產(創建)
● Builder 關注創建時的細節、順序,算是利用了產品的生產結果,操作已生產的產品
Builder 定義 & Builder UML
● Builder 定義
將一個複雜對象的 建構 與 產品(Product
)分離,使同樣的建構過程可以有不同的產品
重點就在建構、產品的分離
● Builder 角色 & UML 如下,有常見的兩種實作方案
A. 標準 Builder 介紹
描述 | 類 | 負責範圍 |
---|---|---|
abstract | Builder | 規範共用方法,實作由子類實現 |
- | ConcreateBuilder | Builder 的實作類,定義 Builder 實做 |
- | Product | Product 的實作類,定義 Product 實做 |
- | Director | 統一 Builder 組裝過程 |
B. 透過「依賴倒置, DIP」概念,讓 Builder 依賴抽象,而不是實做
描述 | 類 | 負責範圍 |
---|---|---|
abstract | Builder | 規範共用方法,實作由子類實現 |
- | ConcreateBuilder | Builder 的實作類,定義 Builder 實做 |
abstract | Product | 產品抽象類,細節由依賴於抽象 (依賴倒置) |
- | ConcreateProduct | Product 的實作類,定義 Product 實做 |
- | Director | 統一 Builder 組裝過程 |
Builder 設計:優缺點
● Builder 設計優點
● 封裝性:使用者不必負擔過多的初始化,只須了解 Director 開出的方法(合約)即可
● 方便控制細節:在創建出物件之前可以在 Builder 檢查、修正
● 產品類 Product
方便拓展 (橫向拓展)
● Builder 設計缺點
● 設計的通病「類的增加」,請分析業務需求後,有這種需求在使用 Builder 模式,否則會增加類,同時增加複雜度
Builder 實現
Builder 標準
A. Builder
抽象類:建構共用的抽象方法 (可以用 interface
or abstract
實現抽象) 並添加 泛型,方便拓展
// Builder 類
// 限制泛型必須是 Computer 的子類
interface ComputerBuilder<T extends Computer> {
ComputerBuilder<T> setBoard(String board);
ComputerBuilder<T> setCPU(String cpu);
ComputerBuilder<T> setPower(int power);
ComputerBuilder<T> setMemory(int memory);
String getBoard();
String getCpu();
int getPower();
int getMemory();
T create();
}
B. ConcreateBuilder
類:實作 ComputerBuilder 接口,並且在內部可以有預設數值,也可以根據使用者的設定做修正
// ConcreateBuilder 類
public class Asus implements ComputerBuilder<Computer> {
private String board = "技嘉", cpu = "AMD";
private int power = 500, memory = 8;
@Override
public ComputerBuilder<Computer> setBoard(String board) {
this.board = board;
return this;
}
@Override
public ComputerBuilder<Computer> setCPU(String cpu) {
this.cpu = cpu;
return this;
}
@Override
public ComputerBuilder<Computer> setPower(int power) {
this.power= power;
return this;
}
@Override
public ComputerBuilder<Computer> setMemory(int memory) {
this.memory = memory;
return this;
}
@Override
public String getBoard() {
return board;
}
@Override
public String getCpu() {
return cpu;
}
@Override
public int getPower() {
return power;
}
@Override
public int getMemory() {
return memory;
}
@Override
public Computer create() {
if(power < 200) {
power = 200;
}
if(memory < 8) {
memory = 8;
}
return new Computer(board, cpu, power, memory);
}
}
● 這裡回傳
this
是否符合最少知識原則呢?如果是回傳自身物件,仍是符合 最少知識原則,因為使用這並無法透過回傳
this
來訪問到其他類如果回傳了其他類超過了兩層,這時就不符合原則
create
函數回傳了一層,還算是可接受範圍
C. Product
類:最終產生的 Computer 產品 (目標類)
// Product 類
public class Computer {
private String board, cpu;
private int power, memory;
public Computer(String b, String c, int p, int m) {
board = b;
cpu = c;
power = p;
memory = m;
}
void setBoard(String board) {
this.board = board;
}
void setCPU(String cpu) {
this.cpu = cpu;
}
void setPower(int power) {
this.power = power;
}
void setMemory(int memory) {
this.memory = memory;
}
public void print() {
System.out.println("CPU is " + cpu + "\n"
+"Board is " + board + "\n"
+"power is " + power + "w\n"
+"memory is " + memory + "G\n"
);
}
}
● 該示例不包含 Product 依賴導致的部分
D. Director
類:透過 Builder 類來創建各種不同的 Product 類,以下創建一個高規格電腦、另一個普通電腦
// Director 類
public class Director {
private final ComputerBuilder<?> computerBuilder;
public Director(ComputerBuilder<?> computerBuilder) {
this.computerBuilder = computerBuilder;
}
public Computer getAsusComputer_Normal() {
return computerBuilder.create(); // 用 default 參數
}
public Computer getAsusComputer_Top() {
return computerBuilder.setCPU("intel i9")
.setMemory(64)
.setPower(1200)
.create();
}
}
● User 使用:透過 ComputerBuilder 來組裝,不必關注細節,透過 create 方法就可以產生你需要的 Computer 類
public class RunComputer {
public static void main(String[] args) {
Director director = new Director(new Asus());
director.getAsusComputer_Normal().print();
System.out.println("-----------------------------------------");
director.getAsusComputer_Top().print();
}
}
--實做--
Builder 變形優化
● 由上面的範例可能出現幾個問題,我們可以做一些優化,但在優化前我們先來做些分析… 看看原先的設計哪裡有問題(或可以改善)
● Product
安全性:如果不想讓使用者直接操作到 Product 類呢?
可以透過 Java Package 的特性,將 Product 限制在 Package 內,並透過建構函數限制... 等等技術(請參考以下範例)
:::info
● 通常對於生產出的產品,我們也會希望它不會受到使用者 setting 而影響到產品的功能(就是生產出啥,使用者就用啥);
所以這次會把 Product 的 setter 功能移除,這也可以加強 Product 安全性
● 簡化結構:除去 Director
角色,這樣結構更加簡單
但相對的,使用者需要直接操控到 Builder
● 優化過後的改動如下
A. Builder 抽象類:調整 ComputerBuilder_2 類,讓其有 getter 將子類的數據返回
public interface ComputerBuilder_2<T extends Computer_2> {
ComputerBuilder_2<T> setBoard(String board);
ComputerBuilder_2<T> setCPU(String cpu);
ComputerBuilder_2<T> setPower(int power);
String getBoard();
String getCpu();
int getPower();
T create();
}
B. ConcreateBuilder
類:實作類 Giga 並沒有太大的修改,重點是在 create
函數時,將自身(this
)傳入,這樣 可以簡化 Product 類的成員
// Builder 實作類
public class Giga implements ComputerBuilder_2<Computer_2> {
private String cpu;
private String board;
private int power;
public Giga(String cpu, String board) {
this.cpu = cpu;
this.board = board;
}
@Override
public ComputerBuilder_2<Computer_2> setBoard(String board) {
this.board = board + "_version_2";
return this;
}
@Override
public ComputerBuilder_2<Computer_2> setCPU(String cpu) {
this.cpu = cpu + "_version_2";
return this;
}
@Override
public ComputerBuilder_2<Computer_2> setPower(int power) {
this.power = power;
return this;
}
@Override
public String getBoard() {
return board;
}
@Override
public String getCpu() {
return cpu;
}
@Override
public int getPower() {
return power;
}
@Override
public Computer_2 create() {
if(power <= 0) {
this.power = 300;
}
// 傳入自身
return new Computer_2(this);
}
}
C. Product
類:修正目標 Computer_2
類別,其中有幾個方法做加強
● 限制 Scope:將 Computer_2
類移動到與 ComputerBuilder_2
相同資料夾,透過 Package 限制其他類對 Computer_2
的訪問
● 限制建構函數:設定 Computer_2
constructor 建構函數,參數為 ComputerBuilder_2
● 限制設定:讓 Computer_2
類單純化,變成一個資料獲取點 (只有 getter)
// Product
public class Computer_2 {
private String board;
private String cpu;
private int power;
public Computer_2(ComputerBuilder_2<?> builder) {
board = builder.getBoard();
cpu = builder.getCpu();
power = builder.getPower();
}
void setBoard(String board) {
this.board = board;
}
void setCPU(String cpu) {
this.cpu = cpu;
}
void setPower(int power) {
this.power = power;
}
public void print() {
System.out.println("CPU is " + cpu + "\n"
+"Board is " + board + "\n"
+"power is " + power + "w\n"
);
}
}
--實做--
針對變形 Builder 修正,UML 圖也需要做部分調整;可以看到 Product 與 Builder 關係更加緊密 (聚合)
Android Source Dialog 視窗
我們最常使用到的彈跳視窗 Dialog 就可以使用 Builder 模式建構
Dialog 基礎使用
// Dialog.java 使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAlertDialog();
}
private void setAlertDialog() {
// Builder 創建 AlertDialog
AlertDialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_launcher_background)
.setMessage("Alert Dialog")
.setTitle("Title")
.setPositiveButton("Positive_Btn", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setTitle("Positive_Btn_Click");
}
})
.setNeutralButton("Neutral_Btn", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setTitle("Neutral_Btn_Click");
}
})
.setNegativeButton("Negative_Btn", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setTitle("Negative_Btn_Click");
}
})
.show();
}
}
AlertDialog 分析:builder 變型
類 | 功能 | 對應腳色 |
---|---|---|
AlertDialog | 創建 AlertController 對象 | Product |
AlertDialog#Builder | Builder 角色,會創建 AlertParams 類,並把設定存到其中 | Builder |
AlertController#AlertParams | 內部儲存許多的屬性參數,透過 apply() 設定 AlertController 中的參數 | 儲存使用者對 Dialog 的設定 |
AlertController | AlertParams 中設定的參數最終會轉嫁到 AlertController | 與 Window 通訊 |
● 首先分析最常使用的 AlertDialog#Builder
類
A. Builder 會先創建一個 AlertParams 來保存使用者設定的數值
B. AlertDialog 是透過 AlertDialog#Builder#create 方法創建
C. AlertDialog 建構函數會創建 AlertController 類
D. 最後將使用者設定從 AlertParams 複製到 AlertController
// AlertDialog.java
public class AlertDialog extends Dialog implements DialogInterface {
// 內部 Builder 類
public static class Builder {
// 參數儲存
private final AlertController.AlertParams P;
public Builder(Context context, int themeResId) {
// 創建參數倉庫 AlertParams
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(@DrawableRes int iconId) {
P.mIconId = iconId;
return this;
}
...
// 創建目標物件,並設定到 AlerDialog 中
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
// @ 追蹤 apply 方法
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
// 創建並展示
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}
● 上面我們知道可以透過 Builder#create 方法創建 AlertDialog 對象 (new),接著看 AlertDialog 的建構函數,知道它會創建一個 AlertController 類
// AlertDialog.java
public class AlertDialog extends Dialog implements DialogInterface {
// AlierDialog 與 AlertController 產生關聯
private AlertController mAlert;
protected AlertDialog(Context context, @StyleRes int themeResId) {
this(context, themeResId, true);
}
// 用 package 限制 constructor
AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
createContextThemeWrapper);
...
// 創建 AlertController
mAlert = AlertController.create(getContext(), this, getWindow());
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
public void setView(View view) {
mAlert.setView(view);
}
public void setIcon(Drawable icon) {
mAlert.setIcon(icon);
}
...
}
● AlertController#Builder#create:透過 AlertParams#apply 將使用者設定,再次設定給 AlertController 對象
// AlertController.java
public class AlertController {
/**
* AlertController#AlertParams 類的 apply 方法
* 將 AlertParams 參數設定到 AlertController 中
*/
public static class AlertParams {
// 將 User 設定在 AlertParams 的設定,賦予給 AlertController
public void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null) {
dialog.setTitle(mTitle);
}
if (mIcon != null) {
dialog.setIcon(mIcon);
}
if (mIconId != 0) {
dialog.setIcon(mIconId);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null);
}
if (mForceInverseBackground) {
dialog.setInverseBackgroundForced(true);
}
// 如果有 items 代表是一個列表 View
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
}
}
}
Dialog 顯示畫面 show:模板模式
● AlertDialog 最終要顯示畫面,會調用到 Dialog#show 方法
// Dialog.java 類
public class Dialog implements DialogInterface, Window.Callback,
KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
private final WindowManager mWindowManager;
View mDecor;
final Window mWindow;
Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId,
boolean createContextThemeWrapper) {
... 準備 context
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w;
... 省略部份
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
public void show() {
// 已經顯示,則直接返回
if (mShowing) {
if (mDecor != null) {
...
mDecor.setVisibility(View.VISIBLE);
}
return;
}
mCanceled = false;
if (!mCreated) {
// onCreate 只會創建一次
// @ 追蹤 dispatchOnCreate 方法
dispatchOnCreate(null);
} else {
// 修正 configuration
final Configuration config = mContext.getResources().getConfiguration();
mWindow.getDecorView().dispatchConfigurationChanged(config);
}
// 每次顯示 Dialog 都會呼叫 onStart 方法
onStart();
mDecor = mWindow.getDecorView();
... 省略部份
WindowManager.LayoutParams l = mWindow.getAttributes();
// 當前有虛擬軟鍵盤,則修要調整 Dialog 顯示大小
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
// 修正 WindowManager#LayoutParams
WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
nl.copyFrom(l);
nl.softInputMode |=
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
l = nl;
}
// 3. 呼叫 Binder 通訊 讓 WMS#addView
mWindowManager.addView(mDecor, l);
mShowing = true;
// 4. 發送 Message 到 Handle
sendShowMessage();
}
}
A. 在建構 Dialog 過程會依序呼叫幾個方法,第一個方法是 dispatchOnCreate
,其實最後就會呼叫到 onCreate
方法 (這個方法相當於 Activity 的 onCreate
方法),AlertDialog 就有 Override onCreate
方法
// Dialog.java
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
protected void onCreate(Bundle savedInstanceState) {
}
// --------------------------------------------------------------
// AlertDialog.java
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
// 需要時可以覆寫 Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// @ 追蹤 installContent 方法
mAlert.installContent();
}
}
● 這其實類似一種模板模式,加載 xml 行為由子類負責
以 AlertDialog 來說就是透過 onCreate 方法,呼叫 AlertContoller 中的 PhoneWindow 加載 xml 布局
B. Dialog 子類可覆寫 Dialog#onStart 方法
// Dialog.java
protected void onStart() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
}
C. Dialog 通過 WindowManager 代理來與 WMS 通訊,目的是把 Dialog 加入視窗內 (addView)
D. 發送顯示消息
private void sendShowMessage() {
if (mShowMessage != null) {
// Obtain a new message so this dialog can be re-used
Message.obtain(mShowMessage).sendToTarget();
}
}
● 這裡我們重點分析 AlertDialog#onCreate 方法 (這個方法起初為 Dialog#dispatchOnCreate 呼叫)
// AlertDialog.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
● 分析 AlertController#installContent 方法:該方法會透過 PhoneWindow 加載 xml 布局(預設是 alert_dialog)
// AlertDialog.java
protected final Window mWindow; // 目前是 PhoneWindow
private int mAlertDialogLayout;
protected AlertController(Context context, DialogInterface di, Window window) {
// 預設布局
mAlertDialogLayout = a.getResourceId(
R.styleable.AlertDialog_layout, R.layout.alert_dialog);
... 省略部份
}
public void installContent() {
int contentView = selectContentView();
// 加載 xml id
mWindow.setContentView(contentView);
// 初始化 AlertDialog 內容
// @ 追蹤 setupView
setupView();
}
// 選擇 layout view
// 預設 xml 為 R.layout.alert_dialog
private int selectContentView() {
if (mButtonPanelSideLayout == 0) {
return mAlertDialogLayout;
}
if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
return mButtonPanelSideLayout;
}
// TODO: use layout hint side for long messages/lists
return mAlertDialogLayout;
}
● PhoneWindow#setContentView 布局加載分析:請參考 LayoutInflate 加載 Xml
● 追蹤 AlertDialog#setUpView 方法:
// AlertDialog.java
// 設定 R.layout.alert_dialog 布局
private void setupView() {
final View parentPanel = mWindow.findViewById(R.id.parentPanel);
// 預設 3 個區塊
final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
// Install custom content before setting up the title or buttons so
// that we can handle panel overrides.
final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
// 設定自定義 View
setupCustomContent(customPanel);
// 3 個區塊的 View
final View customTopPanel = customPanel.findViewById(R.id.topPanel);
final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
// Resolve the correct panels and remove the defaults, if needed.
// 自定義 View 取代 default View
final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
setupContent(contentPanel);
setupButtons(buttonPanel);
setupTitle(topPanel);
... 省略部份
// 設定 ListView
final ListView listView = mListView;
if (listView != null && mAdapter != null) {
listView.setAdapter(mAdapter);
final int checkedItem = mCheckedItem;
if (checkedItem > -1) {
listView.setItemChecked(checkedItem, true);
listView.setSelection(checkedItem);
}
}
}
R.layout.alert_dialog
布局概念圖
● 時序圖
● AlertDialog 整體 UML 圖
類 | 負責功能 |
---|---|
AlertDialog#Builder | 儲存使用者對 Dialog 的設定 |
AlertDialog | 透過 AlertController 控制布局加載 |
Dialog | 透過 WindowManager 添加 Dialog 視窗 |
更多的物件導向設計
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式:Creation Patterns
● 創建模式 PK
● 創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建物件。這些模式可以隱藏創建物件的細節,並提供創建物件的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
● Singleton 單例模式 | 解說實現 | Android Framework Context Service
● Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer
● Factory 工廠方法模式 | 解說實現 | Java 集合設計
● Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗
● Clone 原型模式 | 解說實現 | Android Framework Intent
行為模式:Behavioral Patterns
● 行為模式 PK
● 行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列物件如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
● Stragety 策略模式 | 解說實現 | Android Framework 動畫
● Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService
● Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞
● Specification 規格模式 | 解說實現 | Query 語句實做
● Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計
● Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存
● Visitor 設計模式 | 實現與解說 | 物件導向設計
● Template 設計模式 | 實現與解說 | 物件導向設計
● Mediator 模式設計 | 實現與解說 | 物件導向設計
● Composite 組合模式 | 實現與解說 | 物件導向設計
● Observer 觀察者模式 | JDK Observer | Android Framework Listview
結構模式:Structural Patterns
● 結構模式 PK
● 結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
● Decorate 裝飾模式 | 解說實現 | 物件導向設計
● Iterator 迭代設計 | 解說實現 | 物件導向設計