設計模式學習


一 工廠模式

工廠方法模式是創建型的設計模式之一,Android中的Activity里的各個生命周期方法都有使用到工廠方法

工廠方法的定義及使用場景

在任何需要生成復雜對象的地方,都可以使用工廠方法模式,定義一個用於創建類的接口,讓子類決定實例化哪個類,

工廠模式的通用模式代碼

工廠模式分為標准工廠模式,及其變種工廠模式,
一般來說標准的工廠方法模式需要一個工廠只生產一種產品,那么當產品種類特別多的時候工廠的數量就特別多,所以通常會使用一些工廠方法模式的變種

//抽象產品類
public abstract class Product {
//產品類的抽象方法
public abstract void method();
}

public class ConcreteProductA extends Product{

@Override
public void method() {
System.out.println("具體的產品A");
}
}

public class ConcreteProductB extends Product{

@Override
public void method() {
System.out.println("具體的產品B");
}
}

//抽象工廠類
public abstract class Factroy{
//抽象工廠方法
public abstract Product createProduct();
}

//具體工廠類
public class ConcreteFactory extends Factroy{

@Override
public Product createProduct() {
return new ConcreteProductA();
}
}

//客戶端類
public class Client{
public static void main (String[] args){
Factroy factroy = new ConcreteFactory();
Product p = factroy.createProduct();
p.method();
}
}

上面主要分為四大模塊,一是抽象工廠,其為工廠方法模式的核心;二是具體工廠,其實現了具體的業務邏輯;三是抽象產品,是工廠方法模式所創建的產品的父類;四是具體產品,為實現抽象產品的某個具體產品的對象。
為了更加方便的生產我們所需要的產品,我們可以利用反射的方式來實現:

       //抽象工廠類
public abstract class Factroy{
//抽象工廠方法
public abstract<T extends Product> T createProduct(Class<T> product_cls);
}

//具體工廠類
public class ConcreteFactory extends Factroy{

@Override
public <T extends Product> T createProduct(Class<T> product_cls) {
Product p = null;
try {
p = (Product) Class.forName(product_cls.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T) p;
}
}

//客戶端類
public class Client{
public static void main (String[] args){
Factroy factroy = new ConcreteFactory();
Product p = factroy.createProduct(ConcreteProductA.class);
p.method();
}
}

通過放射,我們在生產所需要的產品時,只需將該產品的class傳入factory的生產函數即可。

二、 抽象工廠模式

抽象工廠模式也是創建型設計模式之一,它跟工廠模式的區別是生產出來的產品是不確定的,它只是為創建一組相關或者相互依賴的對象提供一個接口,而不需要指定它們的具體類。

抽象工廠模式包含四部分:
抽象工廠類:聲明一組用於創建一種產品的方法,每個方法對應一種產品
具體工廠子類:繼承自抽象工廠類,根據當前抽象子類對應的系列,重寫父類定義的對應行為。對應的具體產品不同,行為的實現方式也不同。
抽象產品類:定義當前類型抽象產品的操作,子類繼承父類完成具體的操作。在抽象工廠模式中,可能會有多種抽象類的定義。
具體產品子類:根據當前類型繼承自對應的抽象類,並根據系列的不同重寫抽象類定義的實現。

抽象工廠模式 通用模式//抽象產品類A

public abstract class AbstractProductA {
//每個具體的產品子類需要實現的方法
public abstract void methodA();
}
//抽象產品類
public abstract class AbstractProductB {
//每個具體的產品子類需要實現的方法
public abstract void methodB();
}
//具體產品類A1
public class ConcreteProductA1 extends AbstractProductA{

@Override
public void methodA() {
System.out.println("具體產品A1的方法");
}
}
//具體產品類A2
public class ConcreteProductA2 extends AbstractProductA{

@Override
public void methodA() {
System.out.println("具體產品A2的方法");
}
}
//具體產品類B1
public class ConcreteProductB1 extends AbstractProductB{

@Override
public void methodB() {
System.out.println("具體產品B1的方法");
}
}
//具體產品類B2
public class ConcreteProductB2 extends AbstractProductB{

@Override
public void methodB() {
System.out.println("具體產品B2的方法");
}
}
//抽象工廠類
public abstract class AbstractFactroy{
//創建產品A的方法
public abstract AbstractProductA createProductA();
//創建產品B的方法
public abstract AbstractProductB createProductB();
}
//具體工廠類1
public class ConcreteFactory1 extends AbstractFactroy{

@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}

@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
//具體工廠類2
public class ConcreteFactory2 extends AbstractFactroy{

@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}

@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}

抽象工廠模式顯着的優點就是分離接口與實現,客戶端使用抽象的工廠來創建需要的對象而客戶端根本不知道具體的實現是誰,客戶端只是面向產品的接口編程,使其從具體的產品實現中解耦,同時基於接口和實現的分離,使抽象工廠方法模式在切換產品類時更加靈活、容易,
它的缺點也很明顯,一是對類文件的爆炸性增加,二是不太容易擴展新的產品類,因為每當我們增加一個產品類,就需要修改抽象工廠,那么所有的具體工廠類都需要修改。

三、 單例模式

單例模式是應用最廣的模式之一,許多時候系統只需要一個全局對象,這樣有利於我們協調系統整體的行為,單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統提高這個實例。

單例模式有以下特點
* 單例類只能有一個實例
* 單例類必須自己創建自己的唯一實例
* 單例類必須給所有其他對象提供這一實例
**
單例模式的關鍵點:**
1.構造函數不對外開放,一般為Private
2.通過一個靜態方法或枚舉返回單例類對象
3.確保單例類的對象有且只有一個,尤其是在多線程的環境下
4.確保單例類對象在反序列化時不會重新構建對象

下面是單例模式的幾種實現方式:
1.雙重檢查鎖定DCL:
- 優點:資源利用率高,第一次執行getInstance才會實例化對象,效率高
- 缺點:第一次加載反應慢,也由於Java內存模型的原因偶爾會失敗(由於Java編譯器允許處理器亂序執行,以及JMM中cache、寄存器、到主內存回寫的規定,singleton=new Singleton(); 這句正常的執行順序:
1.改Singleton分配內存
2.調用Singleton()構造函數
3.將singleton對象指定分配的內存空間
可能無法按需要的順序執行,變成 1 - 3 - 2,而導致執行3而未執行2之前被切換到另外一個線程,導致singleton不為空,但是又沒有初始化Singleton,導致DCL失效

    public class Singleton{
private Singleton(){}
private static volatile Singleton slinleton=null;
public static Singleton getInstance()
{
if(singleton==null)
{
synchronized(Singleton.class)
{
if(singleton==null)
{
singleton=new Singleton();
}
}
}
return singleton;
}
}

2.靜態內部類 :推薦使用 ,線程安全

    public class Singleton{
private Singleton(){}
private static class LazyHolder{
private static final Singleton INSTANCE=new Singleton();
}
public static Singleton getInstance()
{
return LazyHolder.INSTANCE;
}
}

在Android系統中,如WidowsManagerService,ActivityManagerService,LayouInflater等類,都是在合適的時候以單例形式注冊在系統中的。

四、 Builder建造者模式

Builder模式是一步一步創建一個復雜對象的創建型模式,將一個復雜對象的構建和它的表示分離,使得同樣的構建過程可以創建不同的表示。
使用場景:
1.相同的方法,不同的執行順序,昌盛不同的事件結果時。
2.多個部件或零件,都可以裝配到一個對象中,但是產生的運行結果又不相同時。
3.產品類非常復雜,或者產品類的調用順序不同產生了不同的作用,這個時候使用建造者非常合適。
4.當初始化一個對象特別復雜,如參數多,且很多參數都具有默認值時。

Builder模式的主要角色:
- Product產品類——產品的抽象類
- Builder ——抽象Builder類,規范產品的組建,一般由子類實現具體的組件過程;
- ConcreteBuilder ——具體的Builder類
- Director ——統一組裝過程。

Builder模式的簡單實現

package com.example.zjz.utils;

import android.content.SyncStatusObserver;
import android.nfc.tech.MifareUltralight;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;

/**
* Created by 5555 on 2017/1/7 0007.
*/

/計算機抽象類
abstract class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOS;

protected Computer() {
}

//設置CPU核心數
public void setBoard(String board) {
mBoard = board;
}

//設置內存
public void setDisplay(String display) {
mDisplay = display;
}

//設置操作系統
public abstract void setmOS();

@Override
public String toString() {
return "Computer [mVoard=" + mBoard + ",mDisplay=" + mDisplay + ",mOS=" + mOS + "]";
}
}
//具體的Computer類,MacBook
class MacBook extends Computer {
@Override
public void setmOS() {
mOS = "Mac OS X 10.10";
}
}
//抽象Builder類
abstract class Builder{
//設置主機
public abstract void buildBoard(String board);
//設置顯示器
public abstract void buildDisplay(String display);
//設置操作系統
public abstract void buildOS();
//創建Computer
public abstract Computer create();
}
//具體的Builder類,
class MacBookBuilder extends Builder{
private Computer mComputer = new MacBook();

@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}

@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}

@Override
public void buildOS() {
mComputer.setmOS();
}

@Override
public Computer create() {
return mComputer;
}
}
//負責構造Builder類
class Director{
Builder mBuilder =null;
public Director(Builder builder){
mBuilder = builder;

}
public void construct(String board, String display){
mBuilder.buildBoard(board);
mBuilder.buildDisplay(display);
mBuilder.buildOS();
}
}


public class TestBuilder{
public static void main(String[] args){
Builder builder = new MacBookBuilder();
Director pcDirector = new Director(builder);
pcDirector.construct("intelBoard","Retina顯示器");
System.out.println("Computerr Info: "+builder.create().toString());
}
}

通過上述代碼,我們可以清晰的看到,通過使用Builder模式,用戶在生成所需類的時候,只需將需要的參數傳入,而不需要知道產品內部的組成細節,具有良好的封裝性,這也體現了建造者模式獨立,且容易擴展的特點。

Builder模式在Android開發中也較為常用,通常作為配置類的構建器將配置的構建和表示分離開來,同時也是將配置從目標類中隔離出來,避免過多的setter方法,Builder常見的實現形式是通過調用鏈實現的使代碼更加的簡潔易懂。

五、 適配器模式

適配器模式在Android中應用十分廣泛,我們常見的ListView、RecyclerView等都需要使用Adapter。
適配器的定義是把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。

使用場景:

1.系統需要使用現有的類,而此類的接口不符合系統的需求,即接口不兼容
2.想要建立一個可以重復使用的類,用於與一些之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
3.需要一個統一的輸出接口,而輸入端的類型不可預知。
適配器模式有三個角色:
- Target :目標角色,就是所期待得到的接口,
- Adaptee:現在需要適配的接口
- Adapter:適配器角色,也是本模式的核心,適配器把原接口裝換成目標接口。顯然,這一角色不可以是接口,而必須是類。

適配器模式分為類適配器模式和對象適配器模式。類適配器模式是用Adapter繼承Adaptee來實現關聯,
而對象適配器是通過Adapter聚合Adaptee的方式實現關聯。

簡單示例

本例是電壓裝換示例,電器工作電壓是5V,而現有電壓是220v,則5V電壓就是Target接口,220V電壓就是Adaptee類,將電壓從220V轉到5V就是Adapter。
- 類適配器模式:

    //Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被轉換的對象
public class Volt220{
public int getVolt220(){
return 220;
}
}
//Adapter角色,將220V的電壓裝換成5V的電壓
public class VoltAdapter extends Volt220 implements FiveVolt{

@Override
public int getVolt5() {
return 5;
}
}
//測試
public class Test{
public static void main(String [] args){
VoltAdapter adapter = new VoltAdapter();
System.out.println("輸出電壓"+adapter.getVolt5());
}
}
  • 對象適配器模式:
    //Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被轉換的對象
public class Volt220{
public int getVolt220(){
return 220;
}
}
//Adapter角色,將220V的電壓裝換成5V的電壓
public class VoltAdapter implements FiveVolt{
Volt200 mVolt220;
pbulic VoltAdapter(Volt220 adaptee){
mVolt220 = adaptee;
}
public int getVolt220(){
return mVolt220.getVolt220();
}
@Override
public int getVolt5() {
return 5;
}
}
//測試
public class Test{
public static void main(String [] args){
VoltAdapter adapter = new VoltAdapter();
System.out.println("輸出電壓"+adapter.getVolt5());
}
}

這種實現方式是將Adaptee傳遞到Adapter中,使用組合的方式實現接口兼容的效果,這比類適配器方式更加靈活,另一個好處就是被適配對象中的方法不會暴露出來。

適配器模式的優缺點

優點:
- 更好的復用性,系統需要使用現有的類,而此類不符合系統的需要,通過適配器模式可以讓這些功能更好的復用
- 更好的擴展性,在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。

缺點:
- 過多的使用適配器,會讓系統非常零亂,不易整體把握,如果不是很有必要,可以不適用適配器,二是直接對系統進行重構。

六 代理模式

代理模式是結構性設計模式,定義是為其他的對象提供一種代理已控制對這個對象的訪問。

使用場景

當無法或不想直接訪問某個對象或訪問某個對象存在困難時,可以通過一個代理對象來間接訪問,為了保證客戶端的使用的透明性,委托對象與代理對象需要實現相同的接口。

通用模式代碼

//抽象主題類
public abstract class Subject{
//普通的業務方法
public abstract void visit();
}
public class RealSubject extends Subject{

@Override
public void visit() {
System.out.println("Real subject");
}
}
//代理類
public class ProxySubject extends Subject{
private RealSubject mSubject; //持有真實主題的引用
public ProxySubject(RealSubject subject){
this.mSubject = subject;
}
@Override
public void visit() {
mSubject.visit();
}
}

//客戶端類
public class Client{
public static void main (String[] args){
//構建一個真實主題對象
RealSubject realSubject = new RealSubject();

//通過真實主題引用的對象構造一個代理對象
ProxySubject proxySubject = new ProxySubject(realSubject);
//調用代理的相關方法
proxySubject.visit();
}
}
  • Subject:抽象主題類,該類的主要職責是聲明真實主題與代理的共同接口方法,該類既可以是一個抽象類也可以是一個接口。
  • RealSubject:真實主題類,該類也稱為主題類或被代理類,定義了代理所表示的真實對象,由其執行具體的業務邏輯方法,而客戶類則通過代理類間接地調用真實主題類中定義的方法。
  • ProxySubject:代理類,該類持有一個對真實主題類的引用,在其所實現的接口方法中調用真實主題類中相應的接口方法執行,以此實現代理的作用。
  • Client:客戶類,即使用代理類的類型。

上面例子所列出的是靜態代理模式,代理模式還有另外一種,就是動態代理模式,

java動態代理創建對象的過程為如下步驟:

1,通過實現 InvocationHandler 接口創建自己的調用處理器;

// InvocationHandlerImpl 實現了 InvocationHandler 接口,並
能實現方法調用從代理類到委托類的分派轉發
// 其內部通常包含指向委托類實例的引用,用於真正執行分派轉發過來的方法調用
InvocationHandler handler = new InvocationHandlerImpl(..);

2,通過為 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;

// 通過 Proxy 為包括 Interface 接口在內的一組接口動態創建代理類的類對象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });

3,通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;

// 通過反射從生成的類對象獲得構造函數對象
Constructor constructor = clazz.getConstructor(new Class[]
{ InvocationHandler.class });

4,通過構造函數創建動態代理類實例,構造時調用處理器對象作為參數被傳入。

// 通過構造函數對象創建動態代理類實例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

為了簡化對象創建過程,Proxy類中的newProxyInstance方法封裝了2~4,只需兩步即可完成代理對象的創建。

// InvocationHandlerImpl 實現了 InvocationHandler 接口
,並能實現方法調用從代理類到委托類的分派轉發
InvocationHandler handler = new InvocationHandlerImpl(..);

// 通過 Proxy 直接創建動態代理類實例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class },
handler );

代理模式的優缺點:

  • 優點:

1.代理作為調用着和真實對象的中間層,降低了模塊間和系統的耦合性

2.可以以一個小對象代理一個大對象,達到優化系統提高運行速度的目的

3.提供RealSubject的權限管理

4.容易擴展,RealSubject和ProxySubject都接口化了,RealSubject更改業務后只要接口不變,ProxySubject可以不做任何修改.

  • 缺點:

1.因為調用者和真實對象多了一個中間層,所以會增加調用響應的時間

七 觀察者模式

觀察者模式常用於 GUI系統,訂閱——發布系統,因為這個模式一個重要作用就是解耦,他的定義是定義對象間的一種一對多的依賴關系,當一個對象的狀態發送改變時,所有依賴於它的對象都能得到通知並被自動更新

使用場景

  • 關聯行為場景,需要注意的是,關聯行為是可拆分的,而不是“組合”關系;
  • 事件多級觸發場景
  • 跨系統的消息交換場景,如消息隊列、事件總線的處理機制

觀察者模式的幾個重要組成。
- 觀察者,我們稱它為Observer,有時候我們也稱它為訂閱者,即Subscriber
- 被觀察者,我們稱它為Observable,即可以被觀察的東西,有時候還會稱之為主題,即Subject

至於觀察者模式的具體實現,這里帶帶大家實現一下場景一,其實Java中提供了Observable類和Observer接口供我們快速的實現該模式,但是為了加深印象,我們不使用這兩個類。

場景1中我們感興趣的事情是天氣預報,於是,我們應該定義一個Weather實體類。

public class Weather {
private String description;

public Weather(String description) {
this.description = description;
}
、、獲取天氣情況
public String getDescription() {
return description;
}
//設置天氣情況
public void setDescription(String description) {
this.description = description;
}

@Override
public String toString() {
return "Weather{" +
"description='" + description + '\'' +
'}';
}
}

然后定義我們的被觀察者,我們想要這個被觀察者能夠通用,將其定義成泛型。內部應該暴露register和unregister方法供觀察者訂閱和取消訂閱,至於觀察者的保存,直接用ArrayList即可,此外,當有主題內容發送改變時,會即時通知觀察者做出反應,因此應該暴露一個notifyObservers方法,以上方法的具體實現見如下代碼。

public class Observable<T> {
List<Observer<T>> mObservers = new ArrayList<Observer<T>>();

public void register(Observer<T> observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!mObservers.contains(observer))
mObservers.add(observer);
}
}

public synchronized void unregister(Observer<T> observer) {
mObservers.remove(observer);
}

public void notifyObservers(T data) {
for (Observer<T> observer : mObservers) {
observer.onUpdate(this, data);
}
}

}

而我們的觀察者,只需要實現一個觀察者的接口Observer,該接口也是泛型的。其定義如下。

    public interface Observer<T> {
void onUpdate(Observable<T> observable,T data);
}

一旦訂閱的主題發送變換就會回調該接口。

我們來使用一下,我們定義了一個天氣變換的主題,也就是被觀察者,還有兩個觀察者觀察天氣變換,一旦變換了,就打印出天氣信息,注意一定要調用被觀察者的register進行注冊,否則會收不到變換信息。而一旦不敢興趣了,直接調用unregister方法進行取消注冊即可

public class Main {
public static void main(String [] args){
Observable<Weather> observable=new Observable<Weather>();
Observer<Weather> observer1=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("觀察者1:"+data.toString());
}
};
Observer<Weather> observer2=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("觀察者2:"+data.toString());
}
};

observable.register(observer1);
observable.register(observer2);


Weather weather=new Weather("晴轉多雲");
observable.notifyObservers(weather);

Weather weather1=new Weather("多雲轉陰");
observable.notifyObservers(weather1);

observable.unregister(observer1);

Weather weather2=new Weather("台風");
observable.notifyObservers(weather2);

}
}

輸出:
觀察者1:Weather{description=’晴轉多雲’}
觀察者2:Weather{description=’晴轉多雲’}
觀察者1:Weather{description=’多雲轉陰’}
觀察者2:Weather{description=’多雲轉陰’}
觀察者2:Weather{description=’台風’}


觀察者模式主要的作用就是對象解耦,將觀察者和被觀察者完全隔離,只依賴於Observer和Observable抽象
- 優點:1
1.觀察者和被觀察者之間是抽象耦合,應對業務變化
2.增強系統的靈活性,可擴展性
- 缺點在應用觀察者模式時應該考慮一下開發效率和運行效率問題,程序中包括一個被觀察者、多個觀察者、開發和調試等內容會比較復雜,

八 策略模式

使用場景

  • 針對同一類型問題的多種處理方式,僅僅是具體行為有差別時
  • 需要安全地封裝多種同一類型的操作時
  • 出現同一抽象類有多個子類,而又需要使用if-else或者switch-case來選擇具體子類時

這個模式涉及到三個角色:

  • 環境(Context)角色:持有一個Strategy的引用。

  •  抽象策略(Strategy)角色:這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。

  • 具體策略(ConcreteStrategy)角色:包裝了相關的算法或行為。

代碼例子

1.角色環境類

public class Context {
//持有一個具體策略的對象
private Strategy strategy;
/**
* 構造函數,傳入一個具體策略對象
* @param strategy 具體策略對象
*/

public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 策略方法
*/

public void contextInterface(){

strategy.strategyInterface();
}

}

2.抽象策略類

public interface MemberStrategy {
/**
* 計算圖書的價格
* @param booksPrice 圖書的原價
* @return 計算出打折后的價格
*/

public double calcPrice(double booksPrice);
}

3.具體策略類(初級會員折扣)

p
ublic class PrimaryMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("對於初級會員的沒有折扣");
return booksPrice;
}

}
4.具體策略類(中級會員折扣)、

public class IntermediateMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("對於中級會員的折扣為10%");
return booksPrice * 0.9;
}

}

5.具體策略類(高級會員折扣)、

public class AdvancedMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("對於高級會員的折扣為20%");
return booksPrice * 0.8;
}
}

6.價格類

public class Price {
//持有一個具體的策略對象
private MemberStrategy strategy;
/**
* 構造函數,傳入一個具體的策略對象
* @param strategy 具體的策略對象
*/

public Price(MemberStrategy strategy){
this.strategy = strategy;
}

/**
* 計算圖書的價格
* @param booksPrice 圖書的原價
* @return 計算出打折后的價格
*/

public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}

  客戶端

public class Client {

public static void main(String[] args) {
//選擇並創建需要使用的策略對象
MemberStrategy strategy = new AdvancedMemberStrategy();
//創建環境
Price price = new Price(strategy);
//計算價格
double quote = price.quote(300);
System.out.println("圖書的最終價格為:" + quote);
}

}

從上面的示例可以看出,策略模式僅僅封裝算法,提供新的算法插入到已有系統中,以及老算法從系統中“退休”的方法,策略模式並不決定在何時使用何種算法。在什么情況下使用什么算法是由客戶端決定的。

策略模式的重心

  策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活,具有更好的維護性和擴展性。

  算法的平等性

  策略模式一個很大的特點就是各個策略算法的平等性。對於一系列具體的策略算法,大家的地位是完全一樣的,正因為這個平等性,才能實現算法之間可以相互替換。所有的策略算法在實現上也是相互獨立的,相互之間是沒有依賴的。

  所以可以這樣描述這一系列策略算法:策略算法是相同行為的不同實現。

  運行時策略的唯一性

  運行期間,策略模式在每一個時刻只能使用一個具體的策略實現對象,雖然可以動態地在不同的策略實現中切換,但是同時只能使用一個。

  公有的行為

  經常見到的是,所有的具體策略類都有一些公有的行為。這時候,就應當把這些公有的行為放到共同的抽象策略角色Strategy類里面。當然這時候抽象策略角色必須要用Java抽象類實現,而不能使用接口。
- 優點

每個算法都獨立於其他,方便單元測試
結構更加清晰,不會像一堆條件語句讓你看着頭暈
客戶端引用的是接口,耦合度更低,擴展性更強
- 缺點

隨着策略增加,子類會增加


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com