
- 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);
}
}
新しいインスタンスを生成して返却することで安定する



