摘要:匹配器是一个一元函数,入参为,返回值为,是一种典型的谓词。执行器也是一个一元函数,入参为,返回值为,其本质就是定制常见的操作,将定义域映射到值域。为一个工厂类,用于生产各种。其中,使用了的。
形式化Functional programming leads to deep insights into the nature of computation. -- Martin Odersky
FizzBuzzWhizz详细描述请自行查阅相关资料。此处以3, 5, 7为例,形式化地描述一下问题。
r1 - times(3) -> Fizz - times(5) -> Buzz - times(7) -> Whizz r2 - times(3) && times(5) && times(7) -> FizzBuzzWhizz - times(3) && times(5) -> FizzBuzz - times(3) && times(7) -> FizzWhizz - times(5) && times(7) -> BuzzWhizz r3 - contains(3) -> Fizz - the priority of contains(3) is highest rd - others -> others
接下来我将使用Scala尝试FizzBuzzWhizz问题的设计和实现。
语义模型从上面的形式化描述,可以很容易地得到FizzBuzzWhizz问题的语义模型。
Rule: (Int) -> String Matcher: (Int) -> Boolean Action: (Int) -> String
其中,Rule存在三种基本的类型:
Rule ::= atom | allof | anyof
三者之间构成了「树型」结构。
atom: (Matcher, Action) -> String allof(rule1, rule2, ...): rule1 && rule2 && ... anyof(rule1, rule2, ...): rule1 || rule2 || ...测试用例
借助Java8增强了的「函数式」能力,可抛弃掉很多重复的「样板代码」,使得设计更加简单、漂亮。此外,Java8构造DSL的能力也相当值得称赞,非常直接,简单。测试用例此处选择Spock(基于Groovy语言),可提高用例的可读性和可维护性。
class RuleSpec extends Specification { private static def spec() { Rule r1_3 = atom(times(3), to("Fizz")) Rule r1_5 = atom(times(5), to("Buzz")) Rule r1_7 = atom(times(7), to("Whizz")) Rule r1 = anyof(r1_3, r1_5, r1_7) Rule r2 = anyof(allof(r1_3, r1_5, r1_7), allof(r1_3, r1_5), allof(r1_3, r1_7), allof(r1_5, r1_7)) Rule r3 = atom(contains(3), to("Fizz")) Rule rd = atom(always(true), nop()) anyof(r3, r2, r1, rd) } def "fizz buzz whizz"() { expect: spec().apply(n) == expect where: n | expect 3 | "Fizz" 5 | "Buzz" 7 | "Whizz" 3 * 5 * 7 | "FizzBuzzWhizz" 3 * 5 | "FizzBuzz" 3 * 7 | "FizzWhizz" (5 * 7) * 2 | "BuzzWhizz" 13 | "Fizz" 35 /* 5*7 */ | "Fizz" /* not "BuzzWhizz" */ 2 | "2" } }匹配器:Matcher
Matcher是一个「一元函数」,入参为Int,返回值为Boolean,是一种典型的「谓词」。从OO的角度看,always是一种典型的Null Object。
import static java.lang.String.valueOf; @FunctionalInterface public interface Matcher { boolean matches(int n); static Matcher times(int n) { return x -> x % n == 0; } static Matcher contains(int n) { return x -> valueOf(x).contains(valueOf(n)); } static Matcher always(boolean bool) { return n -> bool; } }执行器:Action
Action也是一个「一元函数」,入参为Int,返回值为String,其本质就是定制常见的map操作,将定义域映射到值域。
@FunctionalInterface public interface Action { String to(int n); static Action to(String str) { return n -> str; } static Action nop() { return n -> String.valueOf(n); } }规则:Rule
Composition Everywhere
Rule是FizzBuzzWhizz最核心的抽象,也是设计的灵魂所在。从语义上Rule分为2种基本类型,并且两者之间形成了优美的、隐式的「树型」结构,体现了「组合式设计」的强大威力。
Atom
Compositions: anyof, allof
Rule是一个「二元函数」,入参为(Int),返回值为String。
@FunctionalInterface public interface Rule { String apply(int n); }
Rules为一个工厂类,用于生产各种Rule。其中,allof, anyof使用了Java8 Stream的API。
public final class Rules { public static Rule atom(Matcher matcher, Action action) { return n -> matcher.matches(n) ? action.to(n) : ""; } public static Rule anyof(Rule... rules) { return n ->sstream(n, rules) .filter(s -> !s.isEmpty()) .findFirst() .orElse(""); } public static Rule allof(Rule... rules) { return n -> sstream(n, rules) .collect(joining()); } private static Stream源代码sstream(int n, Rule[] rules) { return Arrays.stream(rules) .map(r -> r.apply(n)); } private Rules() { } }
Github: https://github.com/horance-liu/fizz-buzz...
C++11参考实现: https://codingstyle.cn/topics/97
Scala参考实现: https://codingstyle.cn/topics/99
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65591.html
摘要:背景上的一道原题,通过格式划字符串精简了代码结构,省去了很多条件判断语句。题目描述解题思路题目是很简单的,关键是如何优雅地完成是否在当前时间单位后添加和或者,我的代码里运用了很多语句。代码感想表达式真是一个神器。 背景 CodeWar上的一道原题,通过格式划字符串精简了代码结构,省去了很多条件判断语句。 题目描述 Your task in order to complete this ...
摘要:题目从给定字符串中随机出的三字符列表的集合中,恢复原始字符串,并且三字符列表按字符在字符串中出现顺序排列。作为简化,假设秘密字符串中不会有重复字母。从原始集合中去掉找出的第一个字母,并在除去字母的该行末尾添加,以保持三元素列表。 题目:从给定字符串中随机出的三字符列表的集合中,恢复原始字符串,并且三字符列表按字符在字符串中出现顺序排列。作为简化,假设秘密字符串中不会有重复字母。如下: ...
摘要:题目给出一个整型数列表和一个整数,求列表中加起来等于的两个数,并且这一对是在列表中最先组成对的。因为题目要求是返回最先组对成功的两个数,所以要找到列表中符合要求的数对中,第二个数最先出现的数对。与拥有类似的结构。 题目:给出一个整型数列表和一个整数sum,求列表中加起来等于sum的两个数,并且这一对是在列表中最先组成对的。 这道题并不难,使用两个for循环很容易做出来。但提交答案时说出...
阅读 2136·2021-11-19 09:40
阅读 1893·2021-11-08 13:24
阅读 2410·2021-10-18 13:24
阅读 2840·2021-10-11 10:57
阅读 3553·2021-09-22 15:42
阅读 1097·2019-08-29 17:11
阅读 2464·2019-08-29 16:11
阅读 2402·2019-08-29 11:11