利用Lambda重构

  • 环绕执行:重用准备和清理阶段的逻辑,减少重复冗余的代码。

    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;
    } 
    
  • 策略模式

  1. 一个代表某个算法的接口(它是策略模式的接口)。

  2. 一个或多个该接口的具体实现,它们代表了算法的多种实现。

  3. 一个或多个使用策略对象的客户。
    例如:对输入的内容是否根据标准进行了恰当的格式化

     //声明一个函数式接口
     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<>(); 
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容