有点标题党,但是这确实是我最近使用Lambda表达式的感受。设计模式是过去的一些好的经验和套路的总结,但是好的语言特性可以让开发者不去考虑这些设计模式。面向对象常见的设计模式有策略模式、模板方法、观察者模式、责任链模式以及工厂模式,使用Lambda表达式(函数式编程思维)有助于避免面向对象开发中的那些固定代码。下面我们挑选了策略模式和职责链模式两个案例进行分析。
案例1:策略模式当我们解决一个问题有不同的解法的时候,又不希望客户感知到这些解法的细节,这种情况下适合使用策略模式。策略模式包括三个部分:
解决问题的算法(上图中的Strategy);
一个或多个该类算法的具体实现(上图中的ConcreteStrategyA、ConcreteStrategyB和ConcreteStrategyC)
一个或多个客户使用场景(上图中的ClientContext)
面向对象思路首先定义策略接口,表示排序策略:
public interface ValidationStrategy { boolean execute(String s); }然后定义具体的实现类(即不同的排序算法):
public class IsAllLowerCase implements ValidationStrategy { @Override public boolean execute(String s) { return s.matches("[a-z]+"); } } public class IsNumberic implements ValidationStrategy { @Override public boolean execute(String s) { return s.matches("\\d+"); } }最后定义客户使用场景,代码如下图所示。Validator是为客户提供服务时使用的上下文环境,每个Valiator对象中都封装了具体的Strategy对象,在实际工作中,我们可以通过更换具体的Strategy对象来进行客户服务的升级,而且不需要让客户进行升级。
public class Validator { private final ValidationStrategy strategy; public Validator(ValidationStrategy strategy) { this.strategy = strategy; } /** * 给客户的接口 */ public boolean validate(String s) { return strategy.execute(s); } } public class ClientTestDrive { public static void main(String[] args) { Validator numbericValidator = new Validator(new IsNumberic()); boolean res1 = numbericValidator.validate("7780"); System.out.println(res1); Validator lowerCaseValidator = new Validator(new IsAllLowerCase()); boolean res2 = lowerCaseValidator.validate("aaaddd"); System.out.println(res2); } } 函数式编程思路如果使用Lambda表达式考虑,你会发现ValidationStrategy就是一个函数接口(还与Predicate具有同样的函数描述),那么就不需要定义上面那些实现类了,可以直接用下面的代码替换,原因是Lambda表达式内部已经对这些类进行了一定的封装。
public class ClientTestDrive { public static void main(String[] args) { Validator numbericValidator = new Validator((String s) -> s.matches("\\d+")); boolean res1 = numbericValidator.validate("7789"); System.out.println(res1); Validator lowerCaseValidator = new Validator((String s) -> s.matches("[a-z]+")); boolean res2 = lowerCaseValidator.validate("aaaddd"); System.out.println(res2); } } 案例2:责任链模式在某些场景下,需要对一个对象做一系列的工作,这些工作分别是由不同的类完成的,这时候就比较适合使用责任链模式。责任链模式的主要组成部分包括三个:
管理操作序列的抽象类,在该抽象类里有会有一个对象记录当前对象的后继操作对象;
一些具体的操作对象,这些操作对象会以一个链表的形式组织起来
一个使用该模式的客户端组件,该组件只需要跟一个组件打交道就好,不需要跟很多个操作对象耦合在一起。
首先看下我们这里定义了一个抽象类ProcessingObject,其中successor字段用于管理该对象的后继操作对象;handle接口作为对外提供服务的接口;handleWork作为实际处理对象的操作方法。
public abstract class ProcessingObject<T> { protected ProcessingObject<T> successor; public void setSuccessor(ProcessingObject<T> successor) { this.successor = successor; } public T handler(T input) { T r = handleWork(input); if (successor != null) { return successor.handler(r); } return r; } abstract protected T handleWork(T input); }接下来可以定义两个具体的操作对象,如下面代码所示。PS:这里《Java 8实战》书中用的是replaceAll方法是不太合适的,这个点可以参考我们之前的文章——。
public class HeaderTextProcessing extends ProcessingObject<String> { @Override protected String handleWork(String input) { return "From Raoul, Mario and Alan: " + input; } } public class SpellCheckerProcessing extends ProcessingObject<String> { @Override protected String handleWork(String input) { return input.replace("labda", "lambda"); } }