The Coding Kata: FizzBuzzWhizz in Modern C++11

Surprisingly, C++11 feels like a new language. -- Bjarne Stroustrupgit

至今,C++社區仍具備強大的生命力,尤爲自C++11出現後得到了新生。C++到底存在什麼樣的魅力,讓人如此癡狂呢?本文試圖闡述C++的設計思惟,並揭示C++內在的設計本質;最後經過FizzBuzzWhizz的設計和實現一展C++11的風采。程序員

設計思惟

簡單

Make Simple Tasks Simple.github

  • Keep Simple Things Simple閉包

  • Don't Make Complex Things Unnecessarily Complex函數

  • Don't Make Things Impossible性能

Constraint: Don't Cacrifice Performance.測試

平衡

Don’t Over Abstractatom

  • Abstractionscala

  • Performance設計

C++試圖找到「抽象」和「性能」的平衡點,並將抉擇的自由留給了程序員。

自由

  • No One Size Fits All

  • Multi-Paradigm

世界是多樣性的,C++多範式的設計思惟賦予了程序員極大的自由度和靈活性。

友好

  • More and More Expert Friendly

C++愈來愈變得更加友好,這種友好性對於專家感觸將更加深入。

FizzBuzzWhizz

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 || ...

測試用例

藉助C++11加強了的「類型系統」能力,可拋棄掉不少重複的「樣板代碼」,使得設計更加簡單、漂亮。此外,C++11構造DSL的能力也至關值得稱讚,並且很是直接,簡單。

FIXTURE(FizzBuzzWhizzSpec) {
  Rule spec = makeSpec();

  Rule makeSpec() {
    auto r1_3 = atom(times(3), to("Fizz"));
    auto r1_5 = atom(times(5), to("Buzz"));
    auto r1_7 = atom(times(7), to("Whizz"));

    auto r1 = anyof( { r1_3, r1_5, r1_7 });

    auto r2 = anyof({
      allof({ r1_3, r1_5, r1_7 }),
      allof({ r1_3, r1_5 }),
      allof({ r1_3, r1_7 }),
      allof({ r1_5, r1_7 })
    });

    auto r3 = atom(contains(3), to("Fizz"));
    auto rd = atom(always(true), nop());

    return anyof({ r3, r2, r1, rd });
  }

  TEST("fizz buzz whizz") {
    rule(3, "Fizz");
    rule(5, "Buzz");
    rule(7, "Whizz");
    rule(3 * 5 * 7, "FizzBuzzWhizz");
    rule(3 * 5, "FizzBuzz");
    rule(3 * 7, "FizzWhizz");
    rule((5 * 7) * 2, "BuzzWhizz");
    rule(13, "Fizz");
    rule(35 /* 5*7 */, "Fizz");
    rule(2, "2");
  }

  void rule(int n, const std::string& expect) {
    ASSERT_THAT(spec(n), eq(expect));
  }
};

匹配器:Matcher

Matcher是一個「一元函數」,入參爲int,返回值爲bool,是一種典型的「謂詞」。設計採用了C++11函數式的風格,並利用強大的「閉包」能力,讓代碼更加簡潔,並富有表達力。

OO的角度看,always是一種典型的Null Object

using Matcher = std::function<bool(int)>;

Matcher times(int times) {
  return [=](auto n) { 
    return n % times == 0; 
  };
}

Matcher contains(int num) {
  return [=](auto n) { 
    return toString(n).find(toString(num)) != string::npos; 
  };
}

Matcher always(bool value) {
  return [=](auto) { 
    return value; 
  };
}

執行器:Action

Action也是一個「一元函數」,入參爲int,返回值爲std::string,其本質就是定製常見的map操做,將定義域映射到值域。

using Action = std::function<std::string(int)>;

Action to(const std::string& str) {
  return [=](auto) { 
    return str; 
  };
}

Action nop() {
  return [](auto n) { 
    return stdext::toString(n); 
  };
}

規則:Rule

Composition Everywhere

RuleFizzBuzzWhizz最核心的抽象,也是設計的靈魂所在。從語義上Rule分爲2種基本類型,而且二者之間造成了優美的、隱式的「樹型」結構,體現了「組合式設計」的強大威力。

  • Atomic

  • Compositions: anyof, allof

Rule是一個「一元函數」,入參爲int,返回值爲std::string

using Rule = std::function<bool(int, RuleResult&)>;

Rule atom(const Matcher& matcher, const Action& action) {
  return [=](auto n) {
    return matcher(n) ? action(n) : "";
  };
}

Rule anyof(const std::vector<Rule>& rules) {
  return [=](auto n) {
    auto r = std::find_if(rules.begin(), rules.end(),
      [&](const auto& r) { return !r(n).empty(); });
    return r != std::end(rules) ? (*r)(n) : "";
  };
}

Rule allof(const std::vector<Rule>& rules) {
  return [=](auto n) {
    return std::accumulate(rules.begin(), rules.end(), std::string(""),
      [=](const auto& result, const auto& rule) {
        return result + rule(n);
    });
  };
}

源代碼

相關文章
相關標籤/搜索