摘要:例如中的操作數據庫時,先取得數據庫的連接,操作數據后確保釋放連接當操作文件時,先打開文件流,操作文件后確保關閉文件流。例如遍歷文件中所有行,并替換制定模式為其他的字符串。使用實現行為的參數化。
Conditional Deferred Execution 日志LoggerOO makes code understandable by encapsulating moving parting, but FP makes code understandable by minimizing moving parts. -Michael Feathers
if (logger.isLoggable(Level.INFO)) { logger.info("problem:" + getDiagnostic()); }
這個實現存在如下一些壞味道:
重復的樣板代碼,并且散亂到用戶的各個角落;
在logger.debug之前,首先要logger.isLoggable,logger暴露了太多的狀態邏輯,違反了LoD(Law of Demeter)
Apply LoDEliminate Effects Between Unrelated Things.
logger.info("problem:" + getDiagnostic());
public void info(String msg) { if (isLoggable(Level.INFO)) { log(msg) } }
這樣的設計雖然將狀態的查詢進行了封裝,遵循了LoD原則,但依然存在一個嚴重的性能問題。無論如何,getDiagnostic都將得到調用,如果它是一個耗時、昂貴的操作,可能成為系統的瓶頸。
Apply Lambda靈活地應用Lambda惰性求值的特性,可以很漂亮地解決這個問題。
public void log(Level level, Suppliersupplier) { if (isLoggable(level)) { log(supplier.get()); } } public void debug(Supplier supplier) { log(Level.DEBUG, supplier); } public void info(Supplier supplier) { log(Level.INFO, supplier); } ...
用戶的代碼也更加簡潔,省略了那些重復的樣板代碼。
logger.info(() -> "problem:" + getDiagnostic());Apply Scala: Call by Name
在使用lambda時多余的()顯得有點冗余,可以使用by-name參數進一步提高表達力。
def log(level: Level, msg: => String) { if (isLoggable(level)) { log(msg) } } def debug(msg: => String) { log(DEBUG, msg) } def info(msg: => String) { log(INFO, msg) }
logger.info("problem:" + getDiagnostic());
"problem:" + getDiagnostic()語句并非在logger.info展開計算,它被延遲計算直至被apply的時候才真正地被評估和計算。
Execute Around我們經常會遇到一個場景,在執行操作之前,先準備環境,之后再拆除環境。例如XUnit中的setUp/tearDown;操作數據庫時,先取得數據庫的連接,操作數據后確保釋放連接;當操作文件時,先打開文件流,操作文件后確保關閉文件流。
Apply try-finally為了保證異常安全性,在Java7之前,常常使用try-finally的實現模式解決這樣的問題。
public static String process(File file) throws IOException { BufferedReader bf = new BufferedReader(new FileReader(file)); try { return bf.readLine(); } finally { if (bf != null) bf.close(); } }
這樣的設計和實現存在幾個問題:
if (bf != null)是必須的,但常常被人遺忘;
try-finally的樣板代碼遍布在用戶程序中,造成大量的重復設計;
Apply try-with-resources自Java7,只要實現了AutoCloseable的資源類,可以使用try-with-resources的實現模式,進一步簡化上例的樣板代碼。
public String process(File file) throws IOException { try(BufferedReader bf = new BufferedReader(new FileReader(file))) { return bf.readLine(); } }
但是,在某些場景下很難最大化地復用代碼,這使得實現中存在大量的重復代碼。例如遍歷文件中所有行,并替換制定模式為其他的字符串。
public String replace(File file, String regex, String i) throws IOException { try(BufferedReader bf = new BufferedReader(new FileReader(file))) { return bf.readLine().replaceAll(regex, replace); } }Apply Lambda
為了最大化地復用代碼,最小化用戶樣板代碼,將資源操作前后的代碼保持封閉,使用lambda定制與具體問題相關的處理邏輯。
process使用BufferedProcessor實現行為的參數化。
public static String process(File file, BufferedProcessor p) throws IOException { try(BufferedReader bf = new BufferedReader(new FileReader(file))) { return p.process(bf); } }
其中,BufferedProcessor是一個函數式接口,用于描述lambda的原型信息。
@FunctionalInterface public interface BufferedProcessor { String process(BufferedReader bf) throws IOException; }
用戶使用lambda表達式,使得代碼更加簡單、漂亮。
process(file, bf -> bf.readLine());
如果使用Method Reference,可增強表達力。
process(file, BufferedReader::readLine);Apply Scala: Structural Type, Call by Name, Currying
為了最大化地復用資源釋放的實現,使用Scala可以神奇地構造一個簡單的DSL,讓用戶更好地實現復用。
Make it Easy to Reuse.
import scala.language.reflectiveCalls object using { def apply[R <: { def close(): Unit }, T](resource: => R)(f: R => T) = { var res: Option[R] = None try { res = Some(resource) f(res.get) } finally { if (res != None) res.get.close } } }
R <: { def close(): Unit }中泛型參數R是一個擁有close方法的類型;resource: => R將resource聲明為Call by Name,可延遲計算;apply使用了兩個參數,并進行了Currying化。
受益于Currying,用戶的定制的函數可以使用大括號來增強表達力,using猶如內置的語言特性,得到抽象了的控制結構。
using(Source.fromFile(file)) { source => source.getLines }
因為參數source僅僅使用了一次,可以通過占位符進一步增強表達力。
using(Source.fromFile(file)) { _.getLines }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65590.html
摘要:獲取試讀文章高階函數高階函數就是參數為可以為,并且返回值也可為的函數。比方說,我們現在有顧客名單,但我們需要得到他們的郵箱地址我們現在不用高階函數用一個來實現它,代碼如下。 《Refactoring To Collection》 本文是翻譯Adam Wathan 的《Collection To Refactoring》的試讀篇章,這篇文章內容不多,但是可以為我們Laraver使用者能更...
摘要:為了消除重復,可以將查找算法與比較準則這兩個變化方向進行分離。此刻,查找算法的方法名也應該被重命名,使其保持在同一個抽象層次上。結構性重復和存在結構型重復,需要進一步消除重復。 Refactoring to DSL OO makes code understandable by encapsulating moving parting, but FP makes code unders...
摘要:高性能緩存服務器已發布。本次更新主要升級到更改了配置文件關鍵字,刪除了關鍵字為升級到進行了代碼重構。項目主頁本次更新介紹是一個基于的高性能緩存服務器。完全兼容,并且利用的功能來提供非常細致的緩存規則。 高性能緩存服務器 nuster v1.7.10.1 已發布。本次更新主要升級到HAProxy v1.7.10, 更改了配置文件關鍵字,刪除了share關鍵字, 為升級到HAProxy v...
閱讀 2395·2021-11-11 16:54
閱讀 1204·2021-09-22 15:23
閱讀 3645·2021-09-07 09:59
閱讀 1990·2021-09-02 15:41
閱讀 3283·2021-08-17 10:13
閱讀 3037·2019-08-30 15:53
閱讀 1235·2019-08-30 13:57
閱讀 1210·2019-08-29 15:16