多相性の実装パターン
多相性は異なるオブジェクトが同一のインターフェースで異なる振る舞いを実現する仕組みです。例えば、形状計算の場面で円と四角形が共通メソッドで処理されるケースが典型例です。
形状計算の具体例
from abc import ABC, abstractmethod
class GeometricShape(ABC):
@abstractmethod
def compute_area(self):
pass
class CircularShape(GeometricShape):
def __init__(self, radius):
self.radius = radius
def compute_area(self):
return 3.14159 * self.radius ** 2
class RectangularShape(GeometricShape):
def __init__(self, base, height):
self.base = base
self.height = height
def compute_area(self):
return self.base * self.height
def show_area(geometry):
print(f"計算結果: {geometry.compute_area()}")
circle = CircularShape(7)
rectangle = RectangularShape(5, 9)
show_area(circle) # 出力: 計算結果: 153.938
show_area(rectangle) # 出力: 計算結果: 45
この実装ではshow_area関数が形状の種類に依存せず、共通のcompute_areaメソッドを呼び出します。このアプローチにより、新規形状クラスを追加しても既存コードの修正が不要になるため、拡張性が向上します。
カプセル化の実践手法
カプセル化は内部状態を隠蔽し、外部からのアクセスを制御する設計原則です。データの整合性を保ちつつ、実装の変更が外部に影響しないようにします。
プロパティによるアクセス制御
class FinancialAccount:
def __init__(self, owner, start_balance):
self.owner = owner
self.__amount = start_balance # 内部管理用属性
@property
def balance(self):
return self.__amount
@balance.setter
def balance(self, new_value):
if new_value < 0:
raise ValueError("残高はゼロ以上である必要があります")
self.__amount = new_value
def add_funds(self, deposit):
if deposit > 0:
self.__amount += deposit
def deduct_funds(self, withdrawal):
if 0 < withdrawal <= self.__amount:
self.__amount -= withdrawal
my_account = FinancialAccount("佐藤", 5000)
my_account.add_funds(2000)
print(my_account.balance) # 出力: 7000
my_account.balance = 10000 # プロパティ経由で値更新
print(my_account.balance) # 出力: 10000
この例ではbalanceプロパティを介して値の妥当性検証を実施しています。内部実装が変更されても、外部からの呼び出し方法を変更する必要がなく、保守性が向上します。
クラスメソッドと静的メソッドの活用
class DataProcessor:
@classmethod
def create_from_json(cls, json_data):
# JSONデータを解析してインスタンスを生成
return cls(json_data["data"]["value"])
@staticmethod
def convert_units(value, from_unit, to_unit):
conversion_factors = {
("m", "cm"): 100,
("cm", "m"): 0.01
}
return value * conversion_factors.get((from_unit, to_unit), 1)
json_config = {"data": {"value": 42}}
processor = DataProcessor.create_from_json(json_config)
print(DataProcessor.convert_units(5, "m", "cm")) # 出力: 500
クラスメソッドはファクトリーパターンとして、静的メソッドは単純な変換処理に最適です。メソッドの種類を適切に選択することで、コードの目的が明確になり、再利用性が向上します。