Domain Driven Design - Components Chuyên mục Bài Viết Hay 2023-09-12 1.3k Lượt xem 111 Lượt thích 1 Bình luận
Trước đó, chúng ta đã khám phá các khái niệm cơ bản và thuật ngữ được sử dụng trong Domain Driven Design (DDD), cũng như các lớp tạo nên kiến trúc của nó. Trong phần này, chúng ta sẽ đưa ra các ví dụ được sử dụng để kết hợp những khái niệm này và xây dựng ứng dụng của chúng ta, sử dụng PHP như một ví dụ.
Các bài liên quan:
Entity
Các Entity (Thực thể) là các đối tượng có thể truy cập trong ứng dụng của chúng ta và có một định danh duy nhất. Trong thực tế, một Entity là một tập hợp các thuộc tính có một định danh duy nhất. Một dòng trong bảng cơ sở dữ liệu là một ví dụ tốt. Một Entity có tính thay đổi, bởi vì nó có thể thay đổi các thuộc tính của nó và cũng có một vòng đời, có nghĩa là nó có thể bị xóa.
Hãy xem xét "Person" (Người) là một Entity của chúng ta, với "id" là định danh (identifier) (ví dụ: ID sẽ tự động tăng):
<?php
class Person
{
private int $id;
private string $name;
private string $surname;
public function __construct(int $id, string $name, string $surname)
{
$this->id = $id;
$this->name = $name;
$this->surname = $surname;
}
public function id(): int
{
return $this->id;
}
public function name(): string
{
return $this->name;
}
public function surname(): string
{
return $this->surname;
}
}
Value Object (VO)
Không giống với Entity, Value Object (Đối tượng Giá trị) là một đối tượng chứa các thuộc tính nhưng không có định danh khái niệm (no conceptual identity). Chúng là các đối tượng bất biến. Giá trị của chúng không thay đổi và không có vòng đời (điều này có nghĩa rằng chúng không giống như một row trong bảng cơ sở dữ liệu của bạn có thể bị xóa).
Việc đóng gói số ID là kiểu số nguyên vào một đối tượng giá trị ( value object ) (với phương thức so sánh bổ sung) sẽ trông như sau:
<?php
class Id
{
private int $value;
public function __construct(int $value)
{
$this->value = $value;
}
public function value(): int
{
return $this->value;
}
public function isBiggerThan(Id $otherId): bool
{
return $this->value() > $otherId->value();
}
}
Data Transfer Object (DTO)
Đối tượng truyền dữ liệu (Data transfer object - DTO) là một đối tượng mang dữ liệu giữa các quy trình. DTO không có bất kỳ hành vi nào ngoài việc lưu trữ (storage), truy xuất (retrieval), truyền dữ liệu (serialization ) và chuyển dữ liệu (deserialization ) của nó (các phương thức thay đổi, truy cập, phân tích cú pháp và chuyển đổi dữ liệu - mutators, accessors, parsers and serializers). Nói cách khác, DTOs là các đối tượng đơn giản không nên chứa bất kỳ logic kinh doanh (business logic) nào, nhưng có thể chứa cơ chế chuyển đổi và phân cấu dữ liệu để truyền dữ liệu qua mạng.
Để truyền một số dữ liệu của khách hàng đến một phần khác của hệ thống, chúng ta có thể sử dụng DTO sau đây:
<?php
class Client
{
private string $name;
private string $surname;
public function __construct(string $name, string $surname)
{
$this->name = $name;
$this->surname = $surname;
}
public static function fromPrimitives(array $primitives): self
{
return new self((string) $primitives['name'], (string) $primitives['surname']);
}
public function toPrimitives(): array
{
return [
'name' => $this->name,
'surname' => $this->surname,
];
}
public function name(): string
{
return $this->name;
}
public function surname(): string
{
return $this->surname;
}
}
Aggregate
Các đối tượng tổ hợp (Aggregate) đại diện cho một tập hợp các đối tượng có mối quan hệ với nhau, tạo thành một tập hợp các mối quan hệ, với mục tiêu xử lý chúng như một đơn vị. Hơn nữa, chúng cũng có một đối tượng gốc tổ hợp (Aggregate Root). Đối tượng gốc tổ hợp là đối tượng sở hữu các đối tượng khác. Đây là thực thể duy nhất mà bất kỳ đối tượng ngoài tổ hợp nào cũng có thể tham chiếu đến. Ví dụ, một đối tượng Order Line (Dòng Đơn hàng) không có ý nghĩa nếu thiếu một Order (Đơn hàng) để thuộc về, vì vậy chúng ta nói rằng Order là đối tượng gốc tổ hợp.
Hãy xem xét một tổ hợp cơ bản cho ví dụ về Orders (Đơn hàng) và Lines (Dòng) mà chúng ta đã đề cập ở trên:
<?php
final class Order
{
private int $id;
private array $lines = [];
private function __construct(int $orderId)
{
$this->id = $orderId;
}
public static function create(int $orderId): Order
{
return new self($orderId);
}
public function addLine(int $productId, int $quantity): void
{
$lineNumber = count($this->lines) + 1;
$this->lines[] = new OrderLine($lineNumber, $productId, $quantity);
}
public function orderId(): int
{
return $this->id;
}
}
final class OrderLine
{
private int $lineNumber;
private int $productId;
private int $quantity;
public function __construct(int $lineNumber, int $productId, int $quantity)
{
$this->lineNumber = $lineNumber;
$this->productId = $productId;
$this->quantity = $quantity;
}
}
Domain Event
Trong nhiều mô hình kinh doanh, bạn cần có khả năng mô tả các sự kiện xảy ra và thay đổi trạng thái của model. Đối với điều này, bạn có thể sử dụng domain events. Một domain event là bất cứ điều gì xảy ra trong domain model mà có thể đáng quan tâm đối với các phần khác của hệ thống.
Đoạn code sau đây hiển thị interface tối thiểu cho basic domain events và basic event:
<?php
interface DomainEvent
{
public function eventId(): int;
public function occurredOn(): DateTimeImmutable;
}
class UserRegistered implements DomainEvent
{
private int $eventId;
private int $userId;
public function __construct(int $eventId, int $userId)
{
$this->eventId = $eventId;
$this->userId = $userId;
$this->occurredOn = new DateTimeImmutable();
}
public function eventId(): int
{
return $this->eventId;
}
public function userId(): int
{
return $this->userId;
}
public function occurredOn(): DateTimeImmutable
{
return $this->occurredOn;
}
}
Lưu ý: như đã đề cập, sự kiện là điều gì đã xảy ra rồi, vì vậy tên (UserRegistered) phải ở thì quá khứ của động từ.
Service
Thuật ngữ "dịch vụ" (service) đề cập đến một chức năng phần mềm hoặc một tập hợp các chức năng phần mềm (như truy xuất thông tin cụ thể hoặc thực hiện một tập hợp các thao tác) với mục đích mà các khách hàng khác nhau có thể sử dụng lại cho các mục đích khác nhau, cùng với các quy định sẽ kiểm soát cách sử dụng nó.
Repository
Một Repository (Kho dữ liệu) cơ bản là một lớp nằm giữa domain (lĩnh vực)- hay còn gọi là business logic của dự án của bạn và cơ sở dữ liệu (database). Điều này có nghĩa rằng bạn nên nghĩ về cách truy cập dữ liệu trong cơ sở dữ liệu của bạn cùng một cách như bạn làm việc với một collection object tiêu chuẩn.
Người lập trình không cần phải biết chi tiết cần thiết để truy cập cơ sở dữ liệu. Vì cơ sở dữ liệu nằm ở lớp cơ sở hạ tầng (infastructure layer), nó phải xử lý các chi tiết về cơ sở hạ tầng thay vì xử lý về các domain concepts (khái niệm lĩnh vực ).
Cuối cùng, Repository hoạt động như một nơi lưu trữ các đối tượng có thể truy cập toàn cục và cũng có thể bao gồm một chiến lược. Nó có thể truy cập một lưu trữ vẫn còn hoặc khác dựa trên chiến lược cụ thể được chỉ định.
Factory
Trong thế giới của Lập trình hướng đối tượng (OOP), Factory (Xưởng) đề cập đến một đối tượng có trách nhiệm duy nhất là tạo ra các đối tượng khác. Trong Thiết kế Dựa trênDomain-Driven Design, Factories được sử dụng để đóng gói kiến thức cần thiết để tạo đối tượng.
Một ví dụ cơ bản về cách mẫu Factory hoạt động (chúng ta giả định rằng các lớp và giao diện trong phần sử dụng đã được định nghĩa trước):
<?php
use Car;
use Bus;
use Truck;
use VehicleInterface;
class VehicleFactory
{
public static function build(string $type): VehicleInterface
{
if ($type === 'car') {
return new Car();
}
if ($type === 'bus') {
return new Bus();
}
if ($type === 'truck') {
return new Truck();
}
throw new Exception('Type is not defined');
}
}
Bình luận (1)
Cảm ơn Bác