- Value Object採用により仕様を豊かに表現する
- stringやintといった以上のバリデーションができる
もくじ
Value Objectのルール
- 「不変」であること
・setter()をつけてはダメ
・別の値が欲しい時は別途でnewする
Clientクラス
呼び出し
UserConstroller
class UserController { public function _construct() { $this->s_user = app()->make(App\Services\UserService::class); } public function create(CreateUserRequest $request) { $this->s_user->create(new FullName($request->first_name, $request->last_name), new Email($request->email, new Password($request->password))); } public function changePassword(AutoChangePasswordRequest $request) { return $this->s_user->changePaasword(new EntityId($request->user_id), new Password($request->password)); } }
Contextクラス(利用クラス)
UserService
class UserService { public funcrtion _costruct( ) { $this->r_user = app()->make(App\Repository\UserRepository::class); } public function create(FullName $full_name, Email $email, Password $password) { return $this->r_user->createUser($full_name->getFullName(), $email->getEmailAddress, $password->getPassword()); } public function changePassword(EntityId $user_id, Password $password): void { $user = $this->r_user->findWhere([ 'id' => $user_id->getEntityId(), ]); $user->password = $password->getPassword(); $user->save(); } }
FullName型、Email型, Password型でバリデーションできる。
string以上に表現や仕様が豊かになる🐱
Value Objectの例
EntityId
class EntityId { private int $entity_id; public function _construct(int $entity_id) { // マイナスが来たらおかしい if ($entity_id < 0) { throw new ValueObjectException(); } $this->entity_id = $entity_id; } public function getEntityId(): int { return $this->entity_id; } }
class Email { private string $email_address; public function _construct(string $email_address) { // RFCに沿ったメール型であること if (!filter_var($mailaddress, FILTER_VALIDATE_EMAIL) || is_null($email_address)) { throw new ValueObjectException(); } $this->email_address = $email_address; } public function getEmailAddress(): string { return $email_address; } }
FullName
class FullName { private string $first_name; private string $last_name; public function _construct(string $first_name, string $last_name) { $this->first_name = $first_name; $this->last_name = $last_name; } public function getFullName(): string { return sprintf("%s %s", $this->first_name, $this->last_name); } public function getFirstName(): string { return $this->first_name; } public function getLastName(): string { return $this->last_name; } }
Password
class Password { const MIN = 8; private string $password; public function _construct(string $password) { // 8文字以上 if (mb_strlen($password) < $min) { throw new ValueObjectException(); } $this->password = $password } public function getPassword(): string { return $this->password; } }
不変であること
よくあるパターン
$fullname = new FullName($first_name, $last_name); $fullname->changeFirstName($new_first_name);
Value Object ではこうする
$fullname = new FullName($first_name, $last_name); $fullname = new FullName($new_first_name, $last_name);
Value Objectに振る舞いを持たせる
経験値を加算する例
class Experience { private string $industry; private int $amount = 0; public function __construct(int $amount, string $industry) { $this->industry = $industry; $this->amount = $amount; } public function addExperience($amount = $this->amount + $amount, $industry) { if ($this->industry !== $industry) { throw new ValueObjectException(); } return new Experience($amount, $industry); } }
新しいインスタンスを生成して返却することで安定する