FizzBuzzとの3か月(3)

お世話になっております。

3日目の今日は、多態性を取り入れてみます。
多態性ポリモフィズム)については、はてなキーワードを参照してください。
あらかじめお断りしておきますが、これから先は無駄に複雑にしていくつもりです。どうぞご了承ください。

では、さっそくコードをご覧ください。

# -*- coding: sjis -*-

import unittest
import random
import sys


class FizzBuzzFactoryTestCase(unittest.TestCase):
  def setUp(self):
    self._target = FizzBuzzFactory()

  def testgetAnswer(self):
    """1から100までの数をプリントするプログラムを書け。
    ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、
    3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
    """
    self.assertEqual('1', self._target.getAnswer(1))
    self.assertEqual('2', self._target.getAnswer(2))
    self.assertEqual('Fizz', self._target.getAnswer(3))
    self.assertEqual('4', self._target.getAnswer(4))
    self.assertEqual('Buzz', self._target.getAnswer(5))
    self.assertEqual('Fizz', self._target.getAnswer(6))
    self.assertEqual('7', self._target.getAnswer(7))
    self.assertEqual('8', self._target.getAnswer(8))
    self.assertEqual('Fizz', self._target.getAnswer(9))
    self.assertEqual('Buzz', self._target.getAnswer(10))
    self.assertEqual('11', self._target.getAnswer(11))
    self.assertEqual('Fizz', self._target.getAnswer(12))
    self.assertEqual('13', self._target.getAnswer(13))
    self.assertEqual('14', self._target.getAnswer(14))
    self.assertEqual('FizzBuzz', self._target.getAnswer(15))
    self.assertEqual('16', self._target.getAnswer(16))
    self.assertEqual('17', self._target.getAnswer(17))
    self.assertEqual('Fizz', self._target.getAnswer(18))
    self.assertEqual('19', self._target.getAnswer(19))
    self.assertEqual('Buzz', self._target.getAnswer(20))
    self.assertEqual('Fizz', self._target.getAnswer(21))
    self.assertEqual('22', self._target.getAnswer(22))
    self.assertEqual('23', self._target.getAnswer(23))
    self.assertEqual('Fizz', self._target.getAnswer(24))
    self.assertEqual('Buzz', self._target.getAnswer(25))
    self.assertEqual('26', self._target.getAnswer(26))
    self.assertEqual('Fizz', self._target.getAnswer(27))
    self.assertEqual('28', self._target.getAnswer(28))
    self.assertEqual('29', self._target.getAnswer(29))
    self.assertEqual('FizzBuzz', self._target.getAnswer(30))
    self.assertEqual('31', self._target.getAnswer(31))
    self.assertEqual('32', self._target.getAnswer(32))
    self.assertEqual('Fizz', self._target.getAnswer(33))
    self.assertEqual('34', self._target.getAnswer(34))
    self.assertEqual('Buzz', self._target.getAnswer(35))
    self.assertEqual('Fizz', self._target.getAnswer(36))
    self.assertEqual('37', self._target.getAnswer(37))
    self.assertEqual('38', self._target.getAnswer(38))
    self.assertEqual('Fizz', self._target.getAnswer(39))
    self.assertEqual('Buzz', self._target.getAnswer(40))
    self.assertEqual('41', self._target.getAnswer(41))
    self.assertEqual('Fizz', self._target.getAnswer(42))
    self.assertEqual('43', self._target.getAnswer(43))
    self.assertEqual('44', self._target.getAnswer(44))
    self.assertEqual('FizzBuzz', self._target.getAnswer(45))
    self.assertEqual('46', self._target.getAnswer(46))
    self.assertEqual('47', self._target.getAnswer(47))
    self.assertEqual('Fizz', self._target.getAnswer(48))
    self.assertEqual('49', self._target.getAnswer(49))
    self.assertEqual('Buzz', self._target.getAnswer(50))
    self.assertEqual('Fizz', self._target.getAnswer(51))
    self.assertEqual('52', self._target.getAnswer(52))
    self.assertEqual('53', self._target.getAnswer(53))
    self.assertEqual('Fizz', self._target.getAnswer(54))
    self.assertEqual('Buzz', self._target.getAnswer(55))
    self.assertEqual('56', self._target.getAnswer(56))
    self.assertEqual('Fizz', self._target.getAnswer(57))
    self.assertEqual('58', self._target.getAnswer(58))
    self.assertEqual('59', self._target.getAnswer(59))
    self.assertEqual('FizzBuzz', self._target.getAnswer(60))
    self.assertEqual('61', self._target.getAnswer(61))
    self.assertEqual('62', self._target.getAnswer(62))
    self.assertEqual('Fizz', self._target.getAnswer(63))
    self.assertEqual('64', self._target.getAnswer(64))
    self.assertEqual('Buzz', self._target.getAnswer(65))
    self.assertEqual('Fizz', self._target.getAnswer(66))
    self.assertEqual('67', self._target.getAnswer(67))
    self.assertEqual('68', self._target.getAnswer(68))
    self.assertEqual('Fizz', self._target.getAnswer(69))
    self.assertEqual('Buzz', self._target.getAnswer(70))
    self.assertEqual('71', self._target.getAnswer(71))
    self.assertEqual('Fizz', self._target.getAnswer(72))
    self.assertEqual('73', self._target.getAnswer(73))
    self.assertEqual('74', self._target.getAnswer(74))
    self.assertEqual('FizzBuzz', self._target.getAnswer(75))
    self.assertEqual('76', self._target.getAnswer(76))
    self.assertEqual('77', self._target.getAnswer(77))
    self.assertEqual('Fizz', self._target.getAnswer(78))
    self.assertEqual('79', self._target.getAnswer(79))
    self.assertEqual('Buzz', self._target.getAnswer(80))
    self.assertEqual('Fizz', self._target.getAnswer(81))
    self.assertEqual('82', self._target.getAnswer(82))
    self.assertEqual('83', self._target.getAnswer(83))
    self.assertEqual('Fizz', self._target.getAnswer(84))
    self.assertEqual('Buzz', self._target.getAnswer(85))
    self.assertEqual('86', self._target.getAnswer(86))
    self.assertEqual('Fizz', self._target.getAnswer(87))
    self.assertEqual('88', self._target.getAnswer(88))
    self.assertEqual('89', self._target.getAnswer(89))
    self.assertEqual('FizzBuzz', self._target.getAnswer(90))
    self.assertEqual('91', self._target.getAnswer(91))
    self.assertEqual('92', self._target.getAnswer(92))
    self.assertEqual('Fizz', self._target.getAnswer(93))
    self.assertEqual('94', self._target.getAnswer(94))
    self.assertEqual('Buzz', self._target.getAnswer(95))
    self.assertEqual('Fizz', self._target.getAnswer(96))
    self.assertEqual('97', self._target.getAnswer(97))
    self.assertEqual('98', self._target.getAnswer(98))
    self.assertEqual('Fizz', self._target.getAnswer(99))
    self.assertEqual('Buzz', self._target.getAnswer(100))


class FizzBuzzFactory(object):
  def __init__(self):
    self._fizz = Fizz()
    self._buzz = Buzz()
    self._fizzbuzz = FizzBuzz()

  def getAnswer(self, num):
    """numに対応した文字列を返す。"""
    result = None
    if num % 3 == 0 and num % 5 == 0:
      result = self._fizzbuzz
    elif num % 3 == 0:
      result = self._fizz
    elif num % 5 == 0:
      result = self._buzz
    else:
      result = num
    return str(result)

  def execute(self):
    """1から100をパラメータとしてgetAnswerを実行し、復帰値を出力する"""
    for i in range(100):
      param = i + 1
      print(self.getAnswer(param))


class Fizz(object):
  def __str__(self):
    return 'Fizz'


class Buzz(object):
  def __str__(self):
    return 'Buzz'


class FizzBuzz(object):
  def __str__(self):
    return 'FizzBuzz'


if __name__ == '__main__':
  unittest.main()

どのあたりが多態性なのかと申しますと、新しく追加した、Fizz、Buzz、FizzBuzzの3つのクラスです。
これらのクラスが実装しているのは、__str__というメソッドだけです。
このメソッドの定義は以下のとおりです。

Called by the str() built-in function and by the print() function to compute the “informal” string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. The return value must be a string object.

このメソッドをオーバーライドすることで、getAnswerメソッドの最後でstr(result)とすれば、適切な文字列が返るようになっています。
その他の変更点は以下の通りです。

  • FizzBuzzクラスをFizzBuzzFactoryと名前を変更しました。

次は、Fizz、Buzz、FizzBuzz、数字の何を返すかを判断するロジックに手を入れてみたいと思います。

以上