设计模式之函数风工厂模式

大家好, 这里是K字的研究.

前几天在 介绍了如何快速记住java.util.function包下面的所有函数. 这边提一个问题复习下,LongBinaryOperator是干嘛用的?10秒内想不起来的可以去回顾一下.

Function 有入参有返回的叫Function, 特点是有进有出 Consumer

有入参没返回的叫Consumer, 特点是只进不出 

Supplier 没入参有返回的叫Supplier, 特点是只出不进 这个和Callable类似,只是那个是Java5引入的

J K L,公众号:K字的研究如何正确统计字符串里每种字符的个数-你不一定知道的Java基础知识


今天更具体的举例说说为什么要用函数式编程

  • 他们解决了什么痛点
  • 给Java带来了什么新打法
  • 提供了什么新抓手
  • 对Java的顶层设计有什么影响
  • 项目的底层架构有什么改进
  • 对服务链路有什么延伸
  • 对CRUD有什么场景价值
  • 配合设计模式等经典内容能打出怎样的组合拳

好了好了, 不学黑话了.说着玩呢, 今天只说一件事,怎么借助函数式编程写一个工厂模式.

设计模式之函数风工厂模式

设计模式与函数式编程

有了函数式编程, 很多经典GOF设计模式的写法都会变的优雅. 比如最经典,基本上每个人都会入手先学一下的:工厂模式(Factory Pattern).

  1. 先假设我们有一个老婆.
设计模式之函数风工厂模式

  1. 老婆负责给我们提供每天看的东西.
  2. 我们想看什么就告诉老婆, 她会把东西拿过来.
  3. 老婆提供了一个固定清单, 能选择小说,公众号,电视
  • 说要看小说, 就会拿来本《四签名》
  • 说要看公众号,就会拿来老K的《K字的研究》
  • 要看电视, 就会打开《The.Hound.of.the.Baskervilles.1988.720p.BluRay》

在这里, 其实老婆就是一个工厂.东西是他买的,还是自己下载的,怎么弄的,我们完全可以不关心.

类图如下:设计模式之函数风工厂模式

写成代码是这样的:

package sh.now.afk.viz.javaproblem;

interface Watchable {
}

class Novel implements Watchable {
}

class Mp implements Watchable {
}

class Tv implements Watchable {
}

class Aragaki {
    static Watchable get(String kind) {
        switch (kind) {
            case "novel":
                return new Novel();
            case "mp":
                return new Mp();
            case "tv":
                return new Tv();
            default:
                throw new IllegalArgumentException();
        }
    }
}

这里, 可以借助switch. 嗯, 老婆最喜欢的switch来完成这个模式的写法.

设计模式之函数风工厂模式


但是, 有了函数式接口以后, 其实有了更简单的写法.

函数式编程的工厂模式

据我们所知, 跟老婆说要看什么东西以后, 老婆是去调用了一个生成对应东西的方法的.

记得开头复习的java.util.function内容吗? 如果有一个方法,没有入参,但是有返回类型T, 那他叫什么?

Supplier

是的, 老婆其实不需要switch.

根据一个字符串, 去找到一个Supplier,然后调用. 这里其实是一个1v1对应关系. 最合适的类型是?

Map

Map 是提供对应关系最方便的工具. 这里用Map来改写.

import java.nio.file.Watchable;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

class Aragaki {
    static Watchable get(String kind) {
        //这里用if也行
        return Optional.ofNullable(
                        map.get(kind))
                .map(x -> x.get())
                .orElseThrow(IllegalArgumentException::new);
    }
    //这个是java9语法糖,这个of是一个工厂模式.(谁说工厂一定要带Factory
    static final Map<String, Supplier<Watchable>> map = Map.of(
            "novel", Novel::new,
            "mp", Mp::new,
            "tv", Tv::new
    );
}

是不是感觉好像确实优雅了很多.这就是函数式编程的威力.

这里的  Novel::new这个语法, 表示引用Novel的new方法, 这个语法叫 Method Reference(方法引用), 属于函数式编程的半壁江山. 另外半壁是lambda.

一个是有名字的函数, 一个是没名字的函数.  他们统一都是一种叫做:函数式接口的东西.

函数式接口-FunctionalInterface

打开java.util.function内的接口,就可以发现,他们都有一个共同的注解@FunctionalInterface. 标记当前接口是函数式接口. 特点是, 接口的抽象方法(abstract method)只有1个.

老Java中,有很多接收单个抽象方法当参数的地方,现在都可以改造成接收函数式接口了.比如最常用的一个, Comparator

Comparator 函数式接口

比如前几天, 我们按顺序生成天干地支的算法.纪年之间的谁先谁后的比较, 就是自己实现的.

设计模式之函数风工厂模式
生成代码如下
 Seq.of('甲''乙''丙''丁''戊''己''庚''辛''壬''癸')
    .zipWithIndex().innerJoin(
    Seq.of('子''丑''寅''卯''辰''巳''午''未''申''酉''戌''亥')
        .zipWithIndex(),
    (x, y) -> x.v2 % 2 == y.v2 % 2
).sorted((x, y) ->
    (int) ((((x.v1.v2) * 6 - 5 * (x.v2.v2)) + 60) % 60 -
        (((y.v1.v2) * 6 - 5 * (y.v2.v2)) + 60) % 60));

这里的的sorted接收的就是一个Comparator接口. 传入的实现代码是:

(x, y) ->
    (int) ((((x.v1.v2) * 6 - 5 * (x.v2.v2)) + 60) % 60
        - (((y.v1.v2) * 6 - 5 * (y.v2.v2)) + 60) % 60)

因为这里的参数是FunctionalInterface,所以, 可以使用lambda,省下来了不少代码. 按照原有Java逻辑, 要写成这样.

new Comparator<Tuple2<Tuple2<Character, Long>,
    Tuple2<Character, Long>>>() {
  @Override
  public int compare(
      Tuple2<Tuple2<Character, Long>,
          Tuple2<Character, Long>> x,
      Tuple2<Tuple2<Character, Long>,
          Tuple2<Character, Long>> y) {
    return (int) ((x.v1.v2 * 6 - 5 * x.v2.v2 + 60) % 60 -
        (((((y.v1.v2) * 6) - (5 * (y.v2.v2))) + 60) % 60));
  }
}

看着这个, 感觉快要不能呼吸了. FunctionalInterface,改变代码信噪比,可以救命.

后话

没了, 今天这篇就是这么短. 最近在读一本叫《Java Coding Problems》的书. 看到精彩的部分就会把笔记发出来. 

建议去看原书,书中代码十分精彩刺激.

设计模式之函数风工厂模式


文末强烈谴责一位复姓星野的同志,损公肥私.


原文始发于微信公众号(K字的研究):设计模式之函数风工厂模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/24879.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!