-
环绕执行:重用准备和清理阶段的逻辑,减少重复冗余的代码。
String oneLine = processFile((BufferedReader b) -> b.readLine()); String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine()); public static String processFile(BufferedReaderProcessor p) throws IOException { try(BufferedReader br = new BufferedReader(new FileReader("java8inaction/ chap8/data.txt"))){ return p.process(br);//将BufferedReaderProcessor作为执行参数传入 } } public interface BufferedReaderProcessor{ String process(BufferedReader b) throws IOException; }
策略模式
一个代表某个算法的接口(它是策略模式的接口)。
一个或多个该接口的具体实现,它们代表了算法的多种实现。
-
一个或多个使用策略对象的客户。
例如:对输入的内容是否根据标准进行了恰当的格式化//声明一个函数式接口 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 { //获取客户提供的id,提供服务让用户满意,不同的支付通过继承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());
-
观察者模式:
某些事件发生时(比如状态转变),如果一个对象(通常称之为主题)需要自动地通知其他多个对象(称为观察者),就会采用该方案。
例如:
设计并实现一个定制化的通知系统。想法很简单:好几家报纸机构,比如《纽约时报》《卫报》以及《世界报》都订阅了新闻,他们希望当接收的新闻中包含他们感兴趣的关键字时,能得到特别通知。定义一个观察者接口,它将不同的观察者聚合在一起。它仅有一个名为
notify
的方法,一旦接收到一条新的新闻,该方法就会被调用:interface Observer { void notify(String tweet); } interface Subject{ void registerObserver(Observer o);//注册新的观察者 void notifyObservers(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); } } }
实现Subject
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)); } }
Feed类在内部维护了一个观察者列表,一条新闻到达时,它就进行通知。
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!");
由于,
Observer
接口的所有实现类都提供了一个方法:notify
。新闻到达时,它们都只是对同一段代码封装执行。使用Lambda表达式后,你无需显式地实例化三个观察者对象,直接传递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");
}
}
ProcessingObject<String> p1 = new HeaderTextProcessing();
ProcessingObject<String> p2 = new SpellCheckerProcessing();
p1.setSuccessor(p2);
String result = p1.handle("Aren't labdas really sexy?!!");
System.out.println(result); //打印输出“From Raoul, Marioand Alan: Aren't lambdas reallysexy?!!”
//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?!!");
注:
UnaryOperator<T>
的函数描述符为 T -> T
。
-
工厂模式
无需向客户暴露实例化的逻辑就能完成对象的创建。比如,我们假定你为一家银行工作,他们需要一种方式创建不同的金融产品:贷款、期权、股票,等等。public class ProductFactory { 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); } } }
createProduct
方法可以通过附加的逻辑来设置每个创建的产品。但是带来的好处也显而易见,你在创建对象时不用再担心会将构造函数或者配置暴露给客户,这使得客户创建产品时更加简单:Product p = ProductFactory.createProduct("loan");
使用Lambda表达式:
Supplier<T>
的函数描述符() -> T
必须返回一个结果为空的supplier
Supplier<Product> loanSupplier = Loan::new; Loan loan = loanSupplier.get();
利用Lambda重构之前的代码:
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 createProduct(String name){
Supplier<Product> p = map.get(name);
if(p != null) return p.get();
throw new IllegalArgumentException("No such product " + name);
}
若需要多个参数的构造函数,则需要自定义函数式接口:
public interface TriFunction<T, U, V, R>{
R apply(T t, U u, V v);
}
Map<String, TriFunction<Integer, Integer, String, Product>> map
= new HashMap<>();