リファクタリング前
以下のコードを考えます。
Person 内部で Telephone クラスをインスタンス化していますが、電話番号は途中で変更するのではなく値オブジェクトとして新しいインスタンスを生成することが望ましいです。
class Person:
def __init__(self) -> None:
self._telephone_number = Telephone()
@property
def office_area_code(self):
return self._telephone_number.area_code
@office_area_code.setter
def office_area_code(self, arg):
self._telephone_number.area_code = arg
@property
def office_number(self):
return self._telephone_number.number
@office_number.setter
def office_number(self, arg):
self._telephone_number.number = arg
class Telephone:
def __init__(self) -> None:
self._area_code = 'area_code'
self._number = 'number'
@property
def area_code(self):
return self._area_code
@area_code.setter
def area_code(self, arg):
self._area_code = arg
@property
def number(self):
return self._number
@number.setter
def number(self, arg):
self._number = arg
if __name__ == '__main__':
telephone = Telephone()
person = Person()
person.office_area_code = '03'
print(person.office_area_code) # 03
リファクタリング後
リファクタリング後のコードは以下です。
Person のセッター内部で新しいインスタンスを生成してセッターを削除することで Telephone クラスは初期化後に変更が不可となり、値オブジェクトに変更することが可能となります。
from __future__ import annotations
class Person:
def __init__(self) -> None:
self._telephone_number = None
self._office_area_code = ''
self._office_number = ''
@property
def office_area_code(self):
return self._telephone_number.area_code
@office_area_code.setter
def office_area_code(self, arg):
self._telephone_number = Telephone(arg, self._office_number)
@property
def office_number(self):
return self._telephone_number.number
@office_number.setter
def office_number(self, arg):
self._telephone_number = Telephone(self._office_area_code, arg)
class Telephone:
def __init__(self, area_code, number) -> None:
self._area_code = area_code
self._number = number
def __eq__(self, other: Telephone) -> bool:
return self._area_code == other._area_code and self._number == other._number
@property
def area_code(self):
return self._area_code
@property
def number(self):
return self._number
if __name__ == '__main__':
person = Person()
person.office_area_code = '03'
print(person.office_area_code)# 03
また、等価比較メソッド(eq)を定義し機能することをテストコードで検証します。
import pytest
from refactor_a import Telephone
class TestTelehoneNumber:
def test_telephone_equal(self):
assert Telephone('03', '03-1111-1111') == Telephone('03', '03-1111-1111')