5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

kota matsuokaの1人アドベントカレンダー ~Pythonで0からサービスを開発~ Advent Calendar 2018

Day 10

PythonでボトムアップDDD 【エンティティ】

Last updated at Posted at 2018-12-10

ボトムアップドメイン駆動設計エンティティについて、Pythonで書きました。

C#で書かれているコードをPythonに翻訳したので、厳密に再現できていない箇所もあります。また、それぞれの呼び出しをテストコードで表し、ソースコードレベルで目的を明確にしました。

用語の説明やコードの詳細説明に関して、下記の参考文献を参照ください。

参考文献: ボトムアップドメイン駆動設計

筆者が訳した「pythonでボトムアップDDD」
PythonでボトムアップDDD 【値オブジェクト】
PythonでボトムアップDDD 【エンティティ】
PythonでボトムアップDDD 【ドメインサービス】
PythonでボトムアップDDD【値オブジェクト・エンティティ・ドメインサービスを利用する】
PythonでボトムアップDDD 【リポジトリ】
PythonでボトムアップDDD 【テスト用のリポジトリ】
PythonでボトムアップDDD 【ユーザの登録・変更・削除・取得など】

バージョン

  • Python 3.7.0

目次

エンティティとは

詳しいエンティティの説明は、参考文献を参照してください。

ここでは、エンティティの3つの特徴だけおさえておきます。

  • 可変である
  • 同じ属性でも区別される
  • 同一性を持つ

可変である

import dataclasses
import unittest


@dataclasses.dataclass(frozen=True)
class FullName:
    full_name: str


@dataclasses.dataclass
class User:
    def __init__(self, full_name: FullName):
        self.full_name = full_name

    def change_full_name(self, new_name: FullName) -> None:
        if new_name is None:
            raise ValueError(f"{new_name} is invalid argument")

        self.full_name = new_name


class TestUserEntity1(unittest.TestCase):
    def test_属性を変更できる(self):
        user = User(FullName("matsuoka kota"))
        user.change_full_name(FullName("tanaka satoshi"))

        self.assertEqual(FullName("tanaka satoshi"), user.full_name)


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

同じ属性でも区別される

import dataclasses
import unittest
import uuid


@dataclasses.dataclass(frozen=True)
class FullName:
    full_name: str


@dataclasses.dataclass(frozen=True)
class UserId:
    value: str


@dataclasses.dataclass
class User:
    full_name: FullName
    id: UserId


class TestUserEntity2(unittest.TestCase):
    def test_同じ属性でも区別される(self):
        tom1 = User(FullName("Tom Cruise"), UserId(str(uuid.uuid4())))
        tom2 = User(FullName("Tom Cruise"), UserId(str(uuid.uuid4())))

        self.assertNotEqual(tom1, tom2)


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

同一性を持つ

from __future__ import annotations
import dataclasses
import uuid
import unittest


@dataclasses.dataclass(frozen=True)
class FullName:
    full_name: str


@dataclasses.dataclass(frozen=True)
class UserId:
    value: str


@dataclasses.dataclass
class User:
    full_name: FullName
    id: UserId

    def change_full_name(self, new_name: FullName) -> None:
        if new_name is None:
            raise ValueError(f"{new_name} is invalid argument")

        self.full_name = new_name

    def __eq__(self, other: User):
        # idのみで比較する
        return isinstance(other, User) and (self.id == other.id)


class TestUserEntity3(unittest.TestCase):
    def test_オブジェクトの属性が変化しても同一性が保証される(self):
        tom = User(FullName("Tom Cruise"), UserId(str(uuid.uuid4())))

        before_tom = tom

        tom.change_full_name(FullName("Tom Hanks"))

        self.assertEqual(before_tom, tom)


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

参考文献

おまけ

参考文献に載せたブログ記事にはいつも助けられています。ぜひ、みなさんも読みながら、ご自身が使い慣れている言語で写経してみてください。

Renttleというサービスを開発中です。ぜひ、使ってみて、レビューをください。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?