使用Lambda重构面向对象的设计模式
是用Lambda进行重构,主要针对以下五种常见的设计模式: 策略模式 、 模板方法 、观察者模式 、责任链模式 、工厂模式
一、策略模式
策略模式代表了解决一类算法的通用解决方案,你可以在运行时选择使用哪种方案;
验证输入的内容是否根据标准进行了恰当的格式化(比如只包含小写字母或 数字)。你可以从定义一个验证文本(以String的形式表示)的接口入。
public class StrategyMain {
public static void main(String[] args) {
// old school
Validator v1 = new Validator(new IsNumeric());
System.out.println(v1.validate("aaaa"));
Validator v2 = new Validator(new IsAllLowerCase ());
System.out.println(v2.validate("bbbb"));
// with lambdas
Validator v3 = new Validator((String s) -> s.matches("\\d+"));
System.out.println(v3.validate("aaaa"));
Validator v4 = new Validator((String s) -> s.matches("[a-z]+"));
System.out.println(v4.validate("bbbb"));
}
interface ValidationStrategy {
public boolean execute(String s);
}
static private class IsAllLowerCase implements ValidationStrategy {
public boolean execute(String s){
return s.matches("[a-z]+");
}
}
static private class IsNumeric implements ValidationStrategy {
public boolean execute(String s){
return s.matches("\\d+");
}
}
static private class Validator{
private final ValidationStrategy strategy;
public Validator(ValidationStrategy v){
this.strategy = v;
}
public boolean validate(String s){
return strategy.execute(s); }
}
}
Lambda表达式避免了采用策略设计模式时僵化的模板代码
二、模板方法
你需要采用某个算法的框架,同时又希望有一定的灵活度,能对它的某些部分进行改进, 那么采用模板方法设计模式是比较通用的方案。可以使通过Lambda表达式或者方法引用的方式实现;灵活的方式进行修改。
abstract class OnlineBanking {
public void processCustomer(int id){
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy(c);
}
abstract void makeCustomerHappy(Customer c);
// dummy Customer class
static private class Customer {}
// dummy Datbase class
static private class Database{
static Customer getCustomerWithId(int id){ return new Customer();}
}
}
使用Consumer进行消费
public class OnlineBankingLambda {
public static void main(String[] args) {
new OnlineBankingLambda().processCustomer(1337, (Customer c) -> System.out.println("Hello!"));
}
public void processCustomer(int id, Consumer<Customer> makeCustomerHappy){
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy.accept(c);
}
// dummy Customer class
static private class Customer {}
// dummy Database class
static private class Database{
static Customer getCustomerWithId(int id){ return new Customer();}
}
}
可以很方便地通过传递Lambda表达式,直接插入不同的行为,不再需要继承 OnlineBanking类。佐证了Lamba表达式能帮助你解决设计模式与生俱来的设计僵化问题
三、观察者模式
观察者模式是一种比较常见的方案,某些事件发生时(比如状态转变),如果一个对象(通 常我们称之为主题)需要自动地通知其他多个对象(称为观察者),就会采用该方案
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201031173737230.png#pic_center
public class ObserverMain {
public static void main(String[] args) {
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!");
Feed feedLambda = new Feed();
feedLambda.registerObserver((String tweet) -> {
if(tweet != null && tweet.contains("money")){
System.out.println("Breaking news in NY! " + tweet); }
});
feedLambda.registerObserver((String tweet) -> {
if(tweet != null && tweet.contains("queen")){
System.out.println("Yet another news in London... " + tweet); }
});
feedLambda.notifyObservers("Money money money, give me money!");
}
interface Observer{
void inform(String tweet);
}
interface Subject{
void registerObserver(Observer o);
void notifyObservers(String tweet);
}
static private class NYTimes implements Observer{
@Override
public void inform(String tweet) {
if(tweet != null && tweet.contains("money")){
System.out.println("Breaking news in NY!" + tweet);
}
}
}
static private class Guardian implements Observer{
@Override
public void inform(String tweet) {
if(tweet != null && tweet.contains("queen")){
System.out.println("Yet another news in London... " + tweet);
}
}
}
static private class LeMonde implements Observer{
@Override
public void inform(String tweet) {
if(tweet != null && tweet.contains("wine")){
System.out.println("Today cheese, wine and news! " + tweet);
}
}
}
static private 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.inform(tweet));
}
}
}
是否我们随时随地都可以使用Lambda表达式呢?答案是否定的!我们前文介绍的例 子中,Lambda适配得很好,那是因为需要执行的动作都很简单,因此才能很方便地消除僵化代 码。但是,观察者的逻辑有可能十分复杂,它们可能还持有状态,抑或定义了多个方法,诸如此 类。在这些情形下,你还是应该继续使用类的方式。
四、责任链模式
责任链模式是一种创建处理对象序列(比如操作序列)的通用方案。一个处理对象可能需要 在完成一些工作之后,将结果传递给另一个对象,这个对象接着做一些工作,再转交给下一个处 理对象,以此类推。这种模式是通过定义一个代表处理对象的抽象类来实现的,在抽象类中会定义一个字 段来记录后续对象。一旦对象完成它的工作,处理对象就会将它的工作转交给它的后继
public class ChainOfResponsibilityMain {
public static void main(String[] args) {
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);
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 result2 = pipeline.apply("Aren't labdas really sexy?!!");
System.out.println(result2);
}
static private 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);
}
static private class HeaderTextProcessing
extends ProcessingObject<String> {
public String handleWork(String text) {
return "From Raoul, Mario and Alan: " + text;
}
}
static private class SpellCheckerProcessing
extends ProcessingObject<String> {
public String handleWork(String text) {
return text.replaceAll("labda", "lambda");
}
}
}
当然是用也是有一定的局限性的。
另外一个小案例。
public class Letter{
public static String addHeader(String text){
return "From Raoul, Mario and Alan:" + text;
}
public static String addFooter(String text){
return text + "Kind regards";
}
public static String checkSpelling(String text){
return text.replaceAll("C\\+\\+", "**Censored**");
}
public static void main(String...args){
Function<String, String> addHeader = Letter::addHeader;
Function<String, String> transformationPipeline
= addHeader.andThen(Letter::checkSpelling)
.andThen(Letter::addFooter);
System.out.println(transformationPipeline.apply("C++ stay away from me!"));
}
}
五、工厂模式
public class FactoryMain {
public static void main(String[] args) {
Product p1 = ProductFactory.createProduct("loan");
Supplier<Product> loanSupplier = Loan::new;
Product p2 = loanSupplier.get();
Product p3 = ProductFactory.createProductLambda("loan");
}
static private 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);
}
}
public static Product createProductLambda(String name){
Supplier<Product> p = map.get(name);
if(p != null) return p.get();
throw new RuntimeException("No such product " + name);
}
}
static private interface Product {}
static private class Loan implements Product {}
static private class Stock implements Product {}
static private class Bond implements Product {}
final static private Map<String, Supplier<Product>> map = new HashMap<>();
static {
map.put("loan", Loan::new);
map.put("stock", Stock::new);
map.put("bond", Bond::new);
}
}
通过Supplier作为value。
这是个全新的尝试,它使用Java 8中的新特性达到了传统工厂模式同样的效果。但是,如果 工厂方法createProduct需要接收多个传递给产品构造方法的参数,这种方式的扩展性不是很 好。你不得不提供不同的函数接口,无法采用之前统一使用一个简单接口的方式。
假设你希望保存具有三个参数(两个参数为Integer类型,一个参数为String 类型)的构造函数;为了完成这个任务,你需要创建一个特殊的函数接口TriFunction。终 的结果是Map变得更加复杂
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<>();
六、总结
通过使用Lambda表达式,可以简化一些重复性的代码。在往后的工作中需要多总结多使用。