サービス層とリポジトリパターンは、アプリケーションの保守性と拡張性を高めるために非常に重要な設計パターンです。ここでは、これらのパターンをPythonで実装し、具体的な例を通じて理解を深めていきます。
サービス層は、ビジネスロジックを中心に構築され、プレゼンテーション層とデータアクセス層(リポジトリ)との間の仲介役を果たします。これにより、各層の関心事が分離され、疎結合な設計が実現します。
リポジトリパターンは、データアクセスのロジックをカプセル化し、ビジネスロジックから直接データベースの操作を分離します。これにより、データソースの変更が容易になり、テストの際にもモックやスタブを利用しやすくなります。
以下のサンプルでは、簡単なユーザー管理アプリケーションを作成します。ユーザーのデータを管理するために、リポジトリパターンとサービス層を実装します。
まず、ユーザーを表すモデルクラスを定義します。
class User:
def __init__(self, user_id: int, username: str, email: str):
self.user_id = user_id
self.username = username
self.email = email
def __repr__(self):
return f"User(id={self.user_id}, username='{self.username}', email='{self.email}')"
このクラスは、ユーザーのID、ユーザー名、メールアドレスを属性として持ち、__repr__
メソッドをオーバーライドして、ユーザー情報を分かりやすく表示します。
次に、ユーザーを管理するリポジトリクラスを実装します。
class UserRepository:
def __init__(self):
self.users = {} # ユーザーを格納する辞書
def add_user(self, user: User):
self.users[user.user_id] = user
def get_user(self, user_id: int) -> User:
return self.users.get(user_id)
def get_all_users(self) -> list:
return list(self.users.values())
UserRepository
は、ユーザーの追加、取得、全ユーザーの取得機能を提供します。ユーザーは辞書に格納され、IDをキーとして管理されます。
サービス層を実装し、ビジネスロジックを追加します。
class UserService:
def __init__(self, user_repository: UserRepository):
self.user_repository = user_repository
def create_user(self, username: str, email: str) -> User:
user_id = len(self.user_repository.users) + 1 # ユーザーIDを自動生成
user = User(user_id, username, email)
self.user_repository.add_user(user)
return user
def find_user(self, user_id: int) -> User:
return self.user_repository.get_user(user_id)
def list_users(self) -> list:
return self.user_repository.get_all_users()
UserService
は、ユーザーの作成、検索、リスト取得の機能を提供します。リポジトリを通じてデータを操作します。
最後に、これらのクラスを使って実際にユーザーを管理してみましょう。
if __name__ == "__main__":
# リポジトリとサービスのインスタンスを作成
user_repo = UserRepository()
user_service = UserService(user_repo)
# ユーザーの作成
user1 = user_service.create_user("alice", "alice@example.com")
user2 = user_service.create_user("bob", "bob@example.com")
# ユーザーの取得
print("Created Users:")
print(user_service.list_users())
# 特定のユーザーを検索
print("\nSearching for user with ID 1:")
print(user_service.find_user(1))
この構造により、各層が明確に分かれ、テストやメンテナンスが容易になります。リポジトリパターンを利用することで、データソースの変更にも柔軟に対応できるようになります。