空對象模式

概述

在這個快速教程中,咱們將看一下Null對象模式,這是設計模式的一個特例,一個常常被咱們遺忘的特例。咱們將描述它的目的以及咱們什麼時候應該考慮使用它。編程

像往常同樣,咱們還將提供一個簡單的代碼示例。設計模式

空對象模式

在大多數面向對象的編程語言中,咱們會考慮不進行null引用,爲此咱們常常被迫寫空檢查:
Command cmd = getCommand();
if (cmd != null) {
    cmd.execute();
}

有時,若是此類if語句的數量變多,則代碼的可讀性會變得不好,難以閱讀且容易出錯。這是Null對象模式能夠派上用場的時候。編程語言

Null對象模式的目的是最小化這種空檢查。相反,咱們能夠識別null行爲並將其封裝在客戶端代碼所指望的類中。這樣咱們就再也不須要處理空引用的特殊處理。ide

咱們能夠簡單地處理null對象,就像處理實際包含一些更復雜的業務邏輯的給定類型的任何其餘實例同樣,以此來保持代碼的清潔。spa

因爲null對象不該具備任何狀態,所以無需屢次建立相同的實例。所以,咱們常常將null對象實現爲單例設計

Null Object Pattern的UML圖

讓咱們直觀地看一下模式:code

模式圖

咱們能夠看到,會有如下參與者:router

  • 客戶端須要AbstractObject的實例
  • AbstractObject定義客戶指望的執行邏輯- 它還能夠包含實現類的共享邏輯
  • RealObject實現了AbstractObject並提供了真實的行爲
  • NullObject實現AbstractObject並提供do nothing行爲

案例

如今咱們已經清楚地瞭解了這個理論,讓咱們看一個例子。對象

假設一個場景,有一個消息路由器模塊。每條消息都應分配有效的優先級。咱們的系統應該將高優先級消息路由到SMS網關,而具備中等優先級的消息應該路由到JMS隊列。教程

可是,有時會出現「未定義」或空優先級的消息。這些消息應該從進一步處理中丟棄。

首先,咱們將建立路由器接口:

public interface Router {
    void route(Message msg);
}

接下來,讓咱們建立上述接口的兩個實現 - 負責路由到SMS網關的接口以及將消息路由到JMS隊列的接口:

public class SmsRouter implements Router {
    @Override
    public void route(Message msg) {
        // implementation details
    }
}
public class JmsRouter implements Router {
    @Override
    public void route(Message msg) {
        // implementation details
    }
}

最後,讓咱們實現咱們的null對象

public class NullRouter implements Router {
    @Override
    public void route(Message msg) {
        // do nothing
    }
}

咱們如今準備將全部部分組合在一塊兒。讓咱們看看示例客戶端代碼的外觀如何:

public class RoutingHandler {
    public void handle(Iterable<Message> messages) {
        for (Message msg : messages) {
            Router router = RouterFactory.getRouterForMessage(msg);
            router.route(msg);
        }
    }
}

咱們能夠看到,不管RouterFactory返回什麼實現,咱們都以相同的方式處理全部Router對象。這使咱們可以保持代碼的清潔和可讀性。

什麼時候使用空對象模式

咱們應該使用Null對象模式,不然客戶端會檢查null只是爲了跳過執行或執行默認操做。 在這種狀況下,咱們能夠將do nothing邏輯封裝在空對象中,並將其返回給客戶端而不是空值。這樣,若是給定實例爲null,則客戶端代碼再也不須要知道 。

這種方法也遵循通常的面向對象原則。

爲了更好地理解什麼時候應該使用Null對象模式,讓咱們假設咱們必須實現CustomerDao接口,定義以下:

public interface CustomerDao {
    Collection<Customer> findByNameAndLastname(String name, String lastname);
    Customer getById(Long id);
}

若是沒有客戶匹配提供的搜索條件,大多數開發人員將從findByNameAndLastname()返回Collections.emptyList()。這是遵循Null對象模式的一個很好的例子。

相反,getById()應返回具備給定id的客戶。調用此方法的人但願得到特定的客戶實體。若是不存在這樣的客戶,咱們應該顯式返回null以表示提供的ID存在問題。

與全部其餘模式同樣,咱們須要在盲目實現Null對象模式以前考慮咱們的特定用例。不然,咱們可能會無心中在代碼中引入一些很難找到的錯誤。

結論

在本文中,咱們瞭解了Null對象模式是什麼以及什麼時候能夠使用它。咱們還實現了一個設計模式的簡單示例。

關注油膩的Java

相關文章
相關標籤/搜索