読者のあなたならどのような実装を行うかイメージしながら読んでみてほしい。
条件
『サイコロを回すクラス』から利用されることを念頭に置く。
このサイコロクラスは、サイコロを渡されると、ランダムに値を選択する処理になっている。
題
サイコロクラスはどのように実装を拡張するのが良いか
6面,8面サイコロ...というように作成していくとする。
import random
import abc
class Dice(abc.ABC):
"""
サイコロの仕様
"""
__slots__ = () # インスタンスの属性追加を不可にする。
@property
@abc.abstractmethod
def numbers(self) -> set:
...
class DiceRoller:
"""
サイコロを回す役割
ランダムに出目を選択する。
"""
def __init__(self, dice: Dice) -> None:
self._dice: Dice = dice
def roll_dice(self) -> int:
"""
ランダムに選択する。
"""
return random.choice(list(self._dice.numbers))
実装例1 面の数ごとに、愚直に具象クラスを作成する。
抽象クラスの仕様を満たしたサイコロクラスを実装。共通化は行われていない。
この場合、抽象クラスはJavaで言うインターフェイスに近い。
class SixSidedDice(Dice):
"""
6面ダイス
"""
__slots__ = "__numbers"
def __init__(self) -> None:
self.__numbers = {1, 2, 3, 4, 5, 6}
@property
def numbers(self) -> set:
return self.__numbers
class EightSidedDice(Dice):
"""
8面ダイス
"""
__slots__ = "__numbers"
def __init__(self) -> None:
self.__numbers = {1, 2, 3, 4, 5, 6, 7, 8}
@property
def numbers(self) -> set:
return self.__numbers
実装例2 面の数ごとに、テンプレートパターンで共通化しつつ,具象クラスを作成する。
今回の場合、プロパティの実装なんて変わることがないと判断し、
抽象クラスにプロパティの実装をする場合
class Dice(abc.ABC):
"""
サイコロの仕様
"""
__slots__ = "_numbers" # インスタンスの属性追加を不可にする。
def __init__(self) -> None:
self._numbers = None
@property
def numbers(self) -> set:
if self._numbers is None:
raise NotImplementedError('NotImplementedError')
return self._numbers
class SixSidedDice(Dice):
"""
6面ダイス
"""
__slots__ = "_numbers"
def __init__(self) -> None:
super().__init__()
self._numbers = {1, 2, 3, 4, 5, 6}
class EightSidedDice(Dice):
"""
8面ダイス
"""
__slots__ = "_numbers"
def __init__(self) -> None:
super().__init__()
self._numbers = {1, 2, 3, 4, 5, 6, 7, 8}
実装例3 抽象クラスさえ不要と判断し、コンストラクタで切り替える手法を取る。
サイコロの面の数を変えた程度でクラスを別々に作ること自体が愚かだと
抽象クラスをやめて、インスタンス生成時にセットすればよいと判断した場合
class Dice:
"""
サイコロの仕様
"""
__slots__ = "_numbers" # インスタンスの属性追加を不可にする。
def __init__(self, numbers: set) -> None:
self._numbers = numbers
@property
def numbers(self) -> set:
return self._numbers
筆者の見解
サイコロの面の数の仕様程度で、具象クラスに分けるのは、少しやりすぎかもしれない。今回の場合であれば3を筆者は選ぶ。
ただし、抽象クラス(インターフェイス)で仕様を定めて、具象クラスに実装処理を記載するコーディング手法が強力であることには変わりはない
自身が執筆している
https://zenn.dev/timoneko/books/78460a539d033f
OOPの解説のために、少し仰々しく実装した実装例1を載せているが....