設計模式類圖在此鏈接
http://www.lxweimin.com/p/4fe3bb697a8f
“接口隔離”模式:
在組件構建過程中,某些接口之間直接的依賴常常會帶來很多問題,甚至根本無法實現。采用添加一層間接(穩定)接口,來隔離本來互相緊密關聯的接口是一種常見的解決方案。
典型模式
Facade(外觀模式)
Proxy(代理模式)
Adapter(適配器模式)
Meditor(中介者模式)
Facade(外觀模式)
動機(Motivation)
在一個大型代碼外部增加新的特性,會導致新代碼和舊代碼中的子系統產生過多耦合,抵御變化能力降低。
如何簡化外部客戶程序和系統間的交互接口?如何將外部客戶程序的演化和內部子系統的變化之間的依賴相互解耦?
模式定義
為子系統中的一組接口提供一個一直(穩定)的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用(復用)。
——《設計模式》
要點總結
- 從客戶程序的角度來看,Facade模式簡化了整個組件系統的接口,對于組件內部與外部客戶程序來說,達到了一種“解耦”的效果——內部子系統的任何變化不會影響到Facade接口的變化。
- Facade設計模式更注重從框架的層次去看整個系統,而不是單個類的層次。Facade很多時候更是一種架構設計模式。
- Facade設計模式并非一個集裝箱,可以任意地放進任何多個對象。Facade模式中組件的內部應該是“相互耦合關系比較大的一系列組件”,而不是一個簡單的功能集合。
Strategy 策略模式
動機(Motivation)
在軟件構建過程中,某些對象使用的算法可能多種多樣,經常改變,如果將這些算法都編碼到對象中,將會使對象變得異常復雜;而且有時候支持不使用的算法也是一個性能負擔。
如何在運行時根據需要透密地更新對象的算法?將算法與對象本身解耦,從而避免上述問題?
模式定義
定義一系列算法,把它們一個個封裝起來,并且使它們可互相替換(變化)。該模式使得算法可以獨立于使用它的客戶程序(穩定)而變化(擴展,子類化)。
——《設計模式》
abstract class TaxStrategy {
abstract double Calculate(Context context);
}
class CNTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class USTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class DETax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class FRTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
public class SaleOrder {
TaxStrategy taxStrategy;
public SaleOrder(TaxStrategy taxStrategy) {
this.taxStrategy = taxStrategy;
}
public double CalculateTax() {
Context context = null;
double val = taxStrategy.Calculate(context);
return val;
}
}
要點總結
- Strategy及其子類為組件提供了一系列可重用的算法,從而使得類型在運行時方便地根據需要在各個算法之間進行切換。
- Strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句,就是在解耦合。含有許多條件判斷語句的代碼通常都需要Strategy模式。
- 如果Strategy對象沒有實例變量,那么各個上下文可以共享同一個Strategy對象,從而節省對象開銷。
Observer觀察者模式
動機(Motivation)
在軟件構建過程中,我們需要為某些對象建立一種“通知依賴關系”——一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知。如果這樣的依賴關系過于緊密,將使軟件不能很好地抵御變化。
使用面向對象技術,可以將這種依賴關系弱化,并形成一種穩定的依賴關系。從而實現軟件體系結構的松耦合。
模式定義
定義對象間的一種一對多(變化)的依賴關系,以便當一個對象(Subject)的狀態發生改變時,所有依賴于它的對象都得到通知并自動更新。
——《設計模式》
public class MainActivity extends AppCompatActivity {
private Button mAppendButton;
private EditText mEditText;
private TextView mLabelText;
private int count=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppendButton = (Button) findViewById(R.id.appendButton);
mEditText = (EditText) findViewById(R.id.contentEdit);
mLabelText = (TextView) findViewById(R.id.countText);
//訂閱通知
mEditText.addTextChangedListener(textWatcher);
//取消訂閱
//mEditText.removeTextChangedListener(textWatcher);
mAppendButton.setOnClickListener(clickListener);
}
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
String content = mEditText.getText().toString().trim();
//文本框內容處理
content = content + Integer.toString(count);
count++;
mEditText.setText(content);
mEditText.setSelection(content.length());//光標置于末尾
}
};
TextWatcher textWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.i("BeforeTextChanged:", s.toString() );
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.i("OnTextChanged:", s.toString() );
}
public void afterTextChanged(Editable s) {
String count = Integer.toString(s.length());
mLabelText.setText(count);
}
};
}
要點總結
- 增加的Listener會組成一個ArrayList,每當目標對象狀態發生改變,則遍歷ArrayList通知所有觀察者。
- 使用面向對象的抽象,Observer模式使我們可以獨立地改變目標與觀察者,從而使二者之間的依賴關系達致松耦合。
- 目標發送通知時,無需指定觀察者,通知(可以攜帶通知信息作為參數)會自動傳播。
- 觀察者自己決定是否需要訂閱通知,目標對象對此一無所知。
- Observer模式是基于事件的UI框架中非常常用的設計模式,也是MVC模式的一個重要組成部分。
“單一職責”模式:
Decorator(裝飾模式)
Bridge(橋接模式)
Decorator(裝飾模式)
動機(Motivation)
在某些情況下我們可能會“過度地使用繼承來擴展對象的功能”由于繼承為類型引入的靜態特質,使得這種擴展方法缺乏靈活性;并且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹。
如何使“對象功能的擴展”能夠根據需要來動態地實現?同時避免“擴展功能的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響將為最低?
一種較為靈活的方式是將組件嵌入另一個對象中,由這個對象添加功能。我們稱這個嵌入的對象為裝飾。這個裝飾與它所裝飾的組件接口一致,因此它對使用該組件的客戶透明。它將客戶請求轉發給該組件,并且可能在轉發前后執行一些額外的動作。透明性使得你可以遞歸的嵌套多個裝飾,從而可以添加任意多的功能。
模式定義
動態(組合)地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類(繼承)更多靈活(消除重復代碼&減少子類個數)。
——《設計模式》
abstract class Stream {
public abstract char read(int number);
public abstract void seek(int position);
public abstract void write(char data);
}
//主體類
class FileStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class NetworkStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class MemoryStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
//繼承:接口協議
abstract class DecroratorStream extends Stream {
protected Stream s;
protected DecroratorStream(Stream s) { //可以傳遞Stream的子類,根據不同的主體,進行不同的活動
this.s = s;
}
}
class CroptoStream extends DecroratorStream {
//通過調用父類,實例化s
public CroptoStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class BufferedStream extends DecroratorStream{
//通過調用父類,實例化s
public BufferedStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class Client{
public static void main(String[] args) {
FileStream fileStream = new FileStream();
Stream s1 = new CroptoStream(fileStream);
Stream s2 = new BufferedStream(new MemoryStream());
Stream s3 = new CroptoStream(new BufferedStream(new NetworkStream()));
}
}
要點總結
- 通過采用組合而非繼承的手法,Decorator模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能。避免了使用繼承帶來的“靈活性差”和“多子類衍生問題”。
- Decorator類在接口是表現為is-a Component的繼承關系,即Decorator類繼承了Component類所具有的接口。但在實現上又表現為has-a Component的組合關系,即Decorator類又使用了另一個Component類。
- Decorator模式的目的并非解決“多子類衍生的多繼承”問題,Decorator模式應用的要點在于解決“主體類在多個方向上的擴展功能”——是為“裝飾”的含義。
Bridge (橋接模式)
動機(Motivation)
- 由于某些類型的固有的實現邏輯,使得它們具有兩個變化的維度,乃至多個維度的變化。
- 如何應對這種“多維度的變化”?如何利用面向對象技術來使得類型可以輕松地沿著兩個乃至多個方向變化,而不引入額外的復雜度?
模式定義
將抽象部分(業務功能)與實現部分(平臺實現)分離,使它們都可以獨立地變化。
——《設計模式》
abstract class Messager {
MessageImp msgImp; //實現了MessageImp子類的功能
protected Messager(MessageImp msgImp) {
this.msgImp = msgImp;
}
public abstract void login(String username, String password);
public abstract void sendMessage(String message);
public abstract void sendPicture(Image image);
}
abstract class MessageImp{
public abstract void playSound();
public abstract void drawShape();
public abstract void writeText();
public abstract void connect();
}
//平臺實現
class PCMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
class MobileMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
//業務抽象
class MessagerLite extends Messager{
protected MessagerLite(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.drawShape();
}
}
class MessagerPerfect extends Messager{
protected MessagerPerfect(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.playSound();
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.playSound();
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.playSound();
msgImp.drawShape();
}
}
要點總結
- Bridge模式使用“對象間的組合關系”解耦了抽象和實現之間固有的綁定關系,使得抽象和實現可以沿著各自的維度來變化。所謂抽象和實現沿著各自維度的變化,即“子類化”它們。
- Bridge模式有時候類似于多繼承方案,但是多繼承方案往往違背單一職責原則(即一個類只有一個變化的原因),復用性比較差。Bridge模式是比多繼承方案更好的解決方法。
- Bridge模式的應用一般在“兩個非常強的變化維度”,有時一個類也有多于兩個的變化維度,這時可以使用Bridge的擴展模式。
"對象創建“模式:
典型模式
Factory Method(工廠方法)
Abstract Factory(抽象工廠模式)
Prototype(原型模式)
Builder(生成器)
6.Factory Method模式 Factory method模式用于隔離類對象的使用者和具體類型之間的耦合關系。面對一個經常變化的具體類型,緊耦合關系會導致軟件的脆弱。 Factory Method模式通過面對對象的手法,將所要創建的具體對象工作延遲到子類,從而實現一種擴展的策略,較好地解決了這種緊耦合關系。 Factory Method模式解決“單個對象”的需求變化,缺點在于要求創建方法/參數相同。
7.Abstract Factory工廠 該模式主要在于應對“新系列”的需求變動。其缺點在于難以應對“新對象”的需求變動。 如果沒有應對“多系列對象構建”的需求變化,則沒有必須使用這個模式,這時候使用簡單工廠完全可以。
由于設計模式很多,而且設計模式在初學階段一般不做要求,所以對于初學者大家可以不用掌握,但要在設計中逐漸去體會它。