l

2013年10月15日 星期二

Implementation Patterns: Variable State

Oct. 11 10:00~11:41

螢幕快照 2013-10-11 上午11.36.04

Teddy的博士論文裡面曾建議Java例外類別應該要支援Variable State模式。


Teddy之前介紹過三個Kent Beck的實作模式,分別是《Guard Clause》、《Boolean Setting Method》、《Composed Method》,今天介紹另一個也算是蠻常用的實作模式:「Variable State」。

簡而言之,Variable State就是在類別(Class)裡面宣告一個Map這種具有儲存key、value能力的型別,然後用這個Map來儲存資料。看一個例子:

class DataHolder {

  Map<Sttring, Object> data = new HashMap<String, Object>();

  public Object getData(String key) {

      return data.get(key); 

  }

  public void setData(String key, Object value){

      data.set(key, value);

  }

}

相對應於Variable State,另一種更常見的做法叫做Common State(這也是一個實作模式),就是用一般的變數來儲存資料,例如:

class Point {

  int x;

  int y;

}

x和y就是Common StateCommon State還有一些其他的特性,在此就不多做說明。

***

看到這邊鄉民們一定會想,Variable State就這樣,有沒有什麼實際應用的例子?有,Teddy舉一個Kent Beck書上沒有提到的例子:Exception

什麼,怎麼扯來扯去又扯到Exception這個Teddy的法定專長挑眉質疑先談一個例外處理的問題,當錯誤發生的時候,處理錯誤的人(就是你)想要產生一個新的例外往外丟用以代表這個錯誤狀況。再往外傳遞例外之前你想要塞一些額外的資料到例外物件裡面,這樣一來,上一層收到例外的人就可以有更多的資訊可以做為例外處理的參考。但是,以Java語言為例,Java內建的Exception類別只有四種不同的建構元:

  • Exception()
  • Exception(String message) 
  • Exception(String message, Throwable cause)
  • Exception(Throwable cause)

而Exception(嚴格講起來是Throwable)只有setStackTrace(StackTraceElement[] stackTrace)這個method可以在例外物件產生之後用來設定stack trace,並沒有其他的setter method。也就是說,當你產生一個例外物件準備往外丟的時候,最多只能塞進一個String外加一個Throwable物件。如果想要附加額外的資料,就必須自行建立繼承自Exception類別的新例外類別,然後在自己新的例外類別裡面宣告新的變數來儲存資料。例如,

class MyException extends Exception {

  Map<Sttring, Object> data = new HashMap<String, Object>();

  public Object getData(String key) {

      return data.get(key); 

  }

  public void setData(String key, Object value){

      data.set(key, value);

  }

}

這樣一來不管鄉民們要走私或夾帶什麼額外資料到例外物件裡面都沒有問題了。但是,這樣做有一個很嚴重的問題,就是會產生大量的子類別,而這些子類別的出現僅僅只是為了能夠塞一些使用者自訂的資料而已。舉個例子,假設原本Java內建的IOException這個類別就可以代表鄉民們想要表達的例外狀況,但是現在為了能夠多塞一些資料到例外物件裡面,鄉民們被迫就得產生一個MyIOException,然後讓MyIOException實作Variable State

***

寫到這邊不得不說微軟的例外類別就設計得比較好嚎啕大哭,因為它支援了Variable State。有沒有證據?有,.Net的Exception類別有一個Data的Property,用它來實作Variable StateMSDN對於Exception類別的Data屬性說明:「Gets a collection of key/value pairs that provide additional user-defined information about the exception.

以下是節錄自MSDN裡面的範例:

螢幕快照 2013-10-11 上午11.09.05

***

MSDN只說明了Data屬性的用途和提供程式範例,但是它並沒有也不會告訴鄉民們為什麼要這樣設計這就是Teddy經常提到為什麼要學Pattern(不管是Design Pattern、Implementation Pattern、Architecture Pattern、還是HCI Pattern)的原因,因為學了之後除了幫助自己做出更好的設計,還可以了解現存系統或是framework的設計原理,如此一來不但可以加快學習新知的速度,還可以大幅減少誤用的機會。

寫到這邊很自然地應該要順便打個廣告熱戀

***

友藏內心獨白:江湖傳言,有九陽神功護體,學什麼武功都快。

4 則留言:

  1. 有趣。另外,更動態的語言往往讓object可在執行期增減資訊(增減fields, methods...),以Python來說,就是放在每個object都有的__dir__{} dictionary中,以語言方式內建,讓語法更乾淨。

    回覆刪除
  2. hi Teddy,
    I suppose you have a typo:
    public void setDate(String key, Object value){
    public void setData(String key, Object value){

    回覆刪除
    回覆
    1. 感謝您的分享,讓我長知識了,很喜歡您的一句話: 「MSDN只說明了Data屬性的用途和提供程式範例,但是它並沒有也不會告訴鄉民們為什麼要這樣設計。」。知道原理真的很重要,感恩。

      刪除