使用Lambda 重構面向物件的設計模式
新的語言特性常常讓現存的程式設計模式或設計黯然失色。比如, Java 5中引入了for-each迴圈,由於它的穩健性和簡潔性,已經替代了很多顯式使用迭代器的情形。Java 7中推出的菱形操作符(<>)讓大家在建立例項時無需顯式使用泛型,一定程度上推動了Java程式設計師們採用型別介面(type interface)進行程式設計。
對設計經驗的歸納總結被稱為設計模式①。設計軟體時,如果你願意,可以複用這些方式方法來解決一些常見問題。這看起來像傳統建築工程師的工作方式,對典型的場景(比如懸掛橋、拱橋等)都定義有可重用的解決方案。例如,訪問者模式常用於分離程式的演算法和它的操作物件。單例模式一般用於限制類的例項化,僅生成一份物件。
Lambda表示式為程式設計師的工具箱又新添了一件利器。它們為解決傳統設計模式所面對的問題提供了新的解決方案,不但如此,採用這些方案往往更高效、更簡單。使用Lambda表示式後,很多現存的略顯臃腫的面向物件設計模式能夠用更精簡的方式實現了。這一節中,我們會針對五個設計模式展開討論,它們分別是:
策略模式
策略模式代表瞭解決一類演算法的通用解決方案,你可以在執行時選擇使用哪種方案。這一模式應用到更廣泛的領域,比如使用不同的標準來驗證輸入的有效性,使用不同的方式來分析或者格式化輸入。
public interface ValidationStrategy {
boolean execute(String s);
}
public class IsAllLowerCase implements ValidationStrategy {
public boolean execute(String s) {
return s.matches("[a-z]+");
}
}
public class IsNumeric implements ValidationStrategy {
public boolean execute(String s) {
return s.matches("\\d+");
}
}
public class Validator {
private final ValidationStrategy strategy;
public Validator(ValidationStrategy v) {
this.strategy = v;
}
public boolean validate(String s) {
return strategy.execute(s);
}
}
Validator numericValidator = new Validator(new IsNumeric());
boolean b1 = numericValidator.validate("aaaa");
Validator lowerCaseValidator = new Validator(new IsAllLowerCase());
boolean b2 = lowerCaseValidator.validate("bbbb");
lambda
Validator numericValidator = new Validator((String s) -> s.matches("[a-z]+")); boolean b1 = numericValidator.validate("aaaa"); Validator lowerCaseValidator = new Validator((String s) -> s.matches("\\d+")); boolean b2 = lowerCaseValidator.validate("bbbb");
模板方法
如果你需要採用某個演算法的框架,同時又希望有一定的靈活度,能對它的某些部分進行改進,那麼採用模板方法設計模式是比較通用的方案。好吧,這樣講聽起來有些抽象。換句話說,模板方法模式在你“希望使用這個演算法,但是需要對其中的某些行進行改進,才能達到希望的效果”時是非常有用的。
讓我們從一個例子著手,看看這個模式是如何工作的。假設你需要編寫一個簡單的線上銀行應用。通常,使用者需要輸入一個使用者賬戶,之後應用才能從銀行的資料庫中得到使用者的詳細資訊,最終完成一些讓使用者滿意的操作。不同分行的線上銀行應用讓客戶滿意的方式可能還略有不同,比如給客戶的賬戶發放紅利,或者僅僅是少傳送一些推廣檔案。你可能通過下面的抽象類方式來實現線上銀行應用:
abstract class OnlineBanking { public void processCustomer(int id) { Customer c = Database.getCustomerWithId(id); makeCustomerHappy(c); } abstract void makeCustomerHappy(Customer c); } public void processCustomer(int id, Consumer<Customer> makeCustomerHappy) { Customer c = Database.getCustomerWithId(id); makeCustomerHappy.accept(c); } new OnlineBankingLambda().processCustomer(1337,(Customer c)-> System.out.println("Hello "+c.getName());
觀察者模式
觀察者模式是一種比較常見的方案,某些事件發生時(比如狀態轉變),如果一個物件(通常我們稱之為主題)需要自動地通知其他多個物件(稱為觀察者),就會採用該方案。建立圖形使用者介面(GUI)程式時,你經常會使用該設計模式。這種情況下,你會在圖形使用者介面元件(比如按鈕)上註冊一系列的觀察者。如果點選按鈕,觀察者就會收到通知,並隨即執行某個特定的行為。 但是觀察者模式並不侷限於圖形使用者介面。比如,觀察者設計模式也適用於股票交易的情形,多個券商可能都希望對某一支股票價格(主題)的變動做出響應
interface Observer { void notify(String tweet); } class NYTimes implements Observer{ public void notify(String tweet) { if(tweet != null && tweet.contains("money")){ System.out.println("Breaking news in NY! " + tweet); } } } class Guardian implements Observer{ public void notify(String tweet) { if(tweet != null && tweet.contains("queen")){ System.out.println("Yet another news in London... " + tweet); } } } class LeMonde implements Observer{ public void notify(String tweet) { if(tweet != null && tweet.contains("wine")){ System.out.println("Today cheese, wine and news! " + tweet); } } } interface Subject { void registerObserver(Observer o); void notifyObservers(String tweet); } class Feed implements Subject { private final List<Observer> observers = new ArrayList<>(); public void registerObserver(Observer o) { this.observers.add(o); } public void notifyObservers(String tweet) { observers.forEach(o -> o.notify(tweet)); } } @Test public void test() { Feed f = new Feed(); f.registerObserver(new NYTimes()); f.registerObserver(new Guardian()); f.registerObserver(new LeMonde()); f.notifyObservers("The queen said her favourite book is Java 8 in Action!"); //lambda f.registerObserver((String tweet) -> { if (tweet != null && tweet.contains("money")) { System.out.println("Breaking news in NY! " + tweet); } }); f.registerObserver((String tweet) -> { if (tweet != null && tweet.contains("queen")) { System.out.println("Yet another news in London... " + tweet); } }); }
責任鏈模式
public abstract class ProcessingObject<T> { protected ProcessingObject<T> successor; public void setSuccessor(ProcessingObject<T> successor) { this.successor = successor; } public T handle(T input) { T r = handleWork(input); if (successor != null) { return successor.handle(r); } return r; } abstract protected T handleWork(T input); } public class HeaderTextProcessing extends ProcessingObject<String> { public String handleWork(String text){ return "From Raoul, Mario and Alan: " + text; } } public class SpellCheckerProcessing extends ProcessingObject<String> { public String handleWork(String text){ return text.replaceAll("labda", "lambda"); } } @Test public void test12() { ProcessingObject<String> p1 = new HeaderTextProcessing(); ProcessingObject<String> p2 = new SpellCheckerProcessing(); p1.setSuccessor(p2); String result1 = p1.handle("Aren't labdas really sexy?!!"); System.out.println(result1); //lambda UnaryOperator<String> headerProcessing = (String text) -> "From Raoul, Mario and Alan: " + text; UnaryOperator<String> spellCheckerProcessing = (String text) -> text.replaceAll("labda", "lambda"); Function<String, String> pipeline = headerProcessing.andThen(spellCheckerProcessing); String result = pipeline.apply("Aren't labdas really sexy?!!"); }
工廠模式(不太推薦)
public class ProductFactory { final static Map<String, Supplier<Product>> map = new HashMap<>(); static { map.put("loan", Loan::new); map.put("stock", Stock::new); map.put("bond", Bond::new); } public static Product createProductlambda(String name){ Supplier<Product> p = map.get(name); if(p != null) { return p.get(); } throw new IllegalArgumentException("No such product " + name); } public static Product createProduct(String name){ switch(name){ case "loan": return new Loan(); case "stock": return new Stock(); case "bond": return new Bond(); default: throw new RuntimeException("No such product " + name); } } }
public class Product {
}
public class Bond extends Product {
}
public class Loan extends Product {
}
public class Stock extends Product {
}
@Test
public void test22(){
Product p = ProductFactory.createProduct("loan");
Supplier<Product> loanSupplier = Loan::new;
Product product = loanSupplier.get();
Optional<Product> p1 = Optional.of(p);
Optional<Product> p2 = Optional.ofNullable(p);
}
摘自參考:java 8 in action