はじめに
プログラムに携わって一度もFizzBuzz書いたことないなと思ったので、サクッと書いてみました。
せっかくなので保守性高めるようなコードの書き方を意識して、分岐なしのコードをクラス表現を使って実現しています
コード
golangのinterfaceクラスにより処理を分け、mapにより分岐を削除しました。
ポリモーフィズムがあって、mapのようなkeyから設定値を取り出せるものがある言語 であれば はもちろん、無い言語でも配列をうまく扱うなどの工夫により、同様のコードが実現可能です
main.go
package main
import "fmt"
//FizzBuzzのパターン分けをするための構造体
type FizzBuzz struct {
Fizz bool
Buzz bool
}
//パターン網羅する為の構造体生成関数
func NewFizz() FizzBuzz {
return FizzBuzz{Fizz: true, Buzz: false}
}
func NewBuzz() FizzBuzz {
return FizzBuzz{Fizz: false, Buzz: true}
}
func NewFizzBuzz() FizzBuzz {
return FizzBuzz{Fizz: true, Buzz: true}
}
func NewNumber() FizzBuzz {
return FizzBuzz{Fizz: false, Buzz: false}
}
//こっちは各数字用の生成関数
func NewFizzBuzzWithNum(num int) FizzBuzz {
return FizzBuzz{
Fizz: isFizz(num),
Buzz: isBuzz(num),
}
}
func isFizz(num int) bool {
return (num%3 == 0)
}
func isBuzz(num int) bool {
return (num%5 == 0)
}
//Answerのパターンをinterfaceクラスの実装で分ける
type Answer interface {
Answer(int)
}
type AnswerFizz struct {
}
func (a *AnswerFizz) Answer(num int) {
fmt.Println("Fizz!")
}
type AnswerBuzz struct {
}
func (a *AnswerBuzz) Answer(num int) {
fmt.Println("Buzz!")
}
type AnswerFizzBuzz struct {
}
func (a *AnswerFizzBuzz) Answer(num int) {
fmt.Println("FizzBuzz!")
}
type AnswerNumber struct {
}
func (a *AnswerNumber) Answer(num int) {
fmt.Printf("%d\n", num)
}
func main() {
//FizzBuzzのパターンを登録
fizzbuzzMap := map[FizzBuzz]Answer{
NewFizzBuzz(): &AnswerFizzBuzz{},
NewFizz(): &AnswerFizz{},
NewBuzz(): &AnswerBuzz{},
NewNumber(): &AnswerNumber{},
}
for i := 1; i < 50; i++ {
//NewFizzBuzzで今の数字と対応するパターンを取得し、Answer()で実処理実行
fizzbuzzMap[NewFizzBuzzWithNum(i)].Answer(i)
}
}
mapのない言語例として、Cの例を@fujitanozomu さんがコメントに追記してくれました。ありがとうございます!
最後に
FizzBuzz程度で保守性だのクラス定義だのしゃらくせえ!と思ったあなた。私もそう思います。
ただこういう簡単な仕様に対してどう実現しようか考えてみるのも、頭の体操になっていいんじゃないかななんて思いました