摘要:匹配器是一個(gè)一元函數(shù),入?yún)?,返回值為,是一種典型的謂詞。執(zhí)行器也是一個(gè)一元函數(shù),入?yún)?,返回值為,其本質(zhì)就是定制常見的操作,將定義域映射到值域。為一個(gè)工廠類,用于生產(chǎn)各種。其中,使用了的。
形式化Functional programming leads to deep insights into the nature of computation. -- Martin Odersky
FizzBuzzWhizz詳細(xì)描述請(qǐng)自行查閱相關(guān)資料。此處以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問題的設(shè)計(jì)和實(shí)現(xiàn)。
語義模型從上面的形式化描述,可以很容易地得到FizzBuzzWhizz問題的語義模型。
Rule: (Int) -> String Matcher: (Int) -> Boolean Action: (Int) -> String
其中,Rule存在三種基本的類型:
Rule ::= atom | allof | anyof
三者之間構(gòu)成了「樹型」結(jié)構(gòu)。
atom: (Matcher, Action) -> String allof(rule1, rule2, ...): rule1 && rule2 && ... anyof(rule1, rule2, ...): rule1 || rule2 || ...測(cè)試用例
借助Java8增強(qiáng)了的「函數(shù)式」能力,可拋棄掉很多重復(fù)的「樣板代碼」,使得設(shè)計(jì)更加簡單、漂亮。此外,Java8構(gòu)造DSL的能力也相當(dāng)值得稱贊,非常直接,簡單。測(cè)試用例此處選擇Spock(基于Groovy語言),可提高用例的可讀性和可維護(hù)性。
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是一個(gè)「一元函數(shù)」,入?yún)?b>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; } }執(zhí)行器:Action
Action也是一個(gè)「一元函數(shù)」,入?yún)?b>Int,返回值為String,其本質(zhì)就是定制常見的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); } }規(guī)則:Rule
Composition Everywhere
Rule是FizzBuzzWhizz最核心的抽象,也是設(shè)計(jì)的靈魂所在。從語義上Rule分為2種基本類型,并且兩者之間形成了優(yōu)美的、隱式的「樹型」結(jié)構(gòu),體現(xiàn)了「組合式設(shè)計(jì)」的強(qiáng)大威力。
Atom
Compositions: anyof, allof
Rule是一個(gè)「二元函數(shù)」,入?yún)?b>(Int),返回值為String。
@FunctionalInterface public interface Rule { String apply(int n); }
Rules為一個(gè)工廠類,用于生產(chǎn)各種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參考實(shí)現(xiàn): https://codingstyle.cn/topics/97
Scala參考實(shí)現(xiàn): https://codingstyle.cn/topics/99
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65591.html
摘要:這是我在平時(shí)有時(shí)間的時(shí)候做的一些算法上的題目想看更新請(qǐng)移步這里題目描述解法這個(gè)問題當(dāng)時(shí)拿到的時(shí)候是完全沒有思路的,后面上網(wǎng)查詢了一下這個(gè)題目,知道了使用斐波那契數(shù)列就能夠解這道題目,,,當(dāng)然百度作業(yè)幫上面也有相應(yīng)的解法,套路就是題目為一 這是我在平時(shí)有時(shí)間的時(shí)候做的一些算法上的題目 想看更新請(qǐng)移步這里 題目: Climbing Stairs 描述 You are climbing a ...
摘要:背景上的一道原題,通過格式劃字符串精簡了代碼結(jié)構(gòu),省去了很多條件判斷語句。題目描述解題思路題目是很簡單的,關(guān)鍵是如何優(yōu)雅地完成是否在當(dāng)前時(shí)間單位后添加和或者,我的代碼里運(yùn)用了很多語句。代碼感想表達(dá)式真是一個(gè)神器。 背景 CodeWar上的一道原題,通過格式劃字符串精簡了代碼結(jié)構(gòu),省去了很多條件判斷語句。 題目描述 Your task in order to complete this ...
摘要:題目從給定字符串中隨機(jī)出的三字符列表的集合中,恢復(fù)原始字符串,并且三字符列表按字符在字符串中出現(xiàn)順序排列。作為簡化,假設(shè)秘密字符串中不會(huì)有重復(fù)字母。從原始集合中去掉找出的第一個(gè)字母,并在除去字母的該行末尾添加,以保持三元素列表。 題目:從給定字符串中隨機(jī)出的三字符列表的集合中,恢復(fù)原始字符串,并且三字符列表按字符在字符串中出現(xiàn)順序排列。作為簡化,假設(shè)秘密字符串中不會(huì)有重復(fù)字母。如下: ...
摘要:題目給出一個(gè)整型數(shù)列表和一個(gè)整數(shù),求列表中加起來等于的兩個(gè)數(shù),并且這一對(duì)是在列表中最先組成對(duì)的。因?yàn)轭}目要求是返回最先組對(duì)成功的兩個(gè)數(shù),所以要找到列表中符合要求的數(shù)對(duì)中,第二個(gè)數(shù)最先出現(xiàn)的數(shù)對(duì)。與擁有類似的結(jié)構(gòu)。 題目:給出一個(gè)整型數(shù)列表和一個(gè)整數(shù)sum,求列表中加起來等于sum的兩個(gè)數(shù),并且這一對(duì)是在列表中最先組成對(duì)的。 這道題并不難,使用兩個(gè)for循環(huán)很容易做出來。但提交答案時(shí)說出...
閱讀 2267·2021-11-19 09:40
閱讀 1958·2021-11-08 13:24
閱讀 2493·2021-10-18 13:24
閱讀 2894·2021-10-11 10:57
閱讀 3611·2021-09-22 15:42
閱讀 1146·2019-08-29 17:11
閱讀 2562·2019-08-29 16:11
閱讀 2448·2019-08-29 11:11