Agregat, Repositori dan Factory
Lindungi invarian dengan agregat dan kekalkannya secara kemas.
Agregat, Repositori dan Factory ialah pelajaran PHP Academy percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran PHP Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus PHP Academy merangkumi sejumlah 4 pelajaran.
Melindungi invarian
Setelah anda mempunyai entiti dan objek nilai, anda memerlukan corak untuk memastikan kelompoknya kekal konsisten dan disimpan dengan kemas. DDD menjawabnya dengan tiga corak taktikal: Agregat (sempadan konsistensi), Repositori (abstraksi penyimpanan seperti koleksi) dan Kilang (pembinaan kompleks). Pelajaran ini menunjukkan cara semuanya digabungkan dalam PHP.
Apakah Agregat
Sebuah agregat ialah kelompok entiti dan objek nilai yang dianggap sebagai satu unit untuk perubahan data. Satu entiti ialah akar agregat — satu-satunya ahli yang boleh dirujuk oleh kod luar. Semua pengubahsuaian mesti melalui akar tersebut, yang menguatkuasakan invarian agregat. Agregat juga merupakan sempadan transaksi: ia dimuatkan dan disimpan secara atomik.
Akar melindungi keseluruhan
Pemanggil luar tidak pernah menyentuh ahli dalaman secara langsung. Untuk menambah item baris, anda memanggil kaedah pada akar, yang mengesahkan dan mengekalkan konsistensi (jumlah, had). Ini memastikan invarian berada di satu tempat.
<?php
final class LineItem {
public function __construct(
public readonly string $sku,
public readonly int $qty,
public readonly int $unitCents
) {}
public function subtotal(): int { return $this->qty * $this->unitCents; }
}
final class Order { // Aggregate Root
/** @var LineItem[] */
private array $items = [];
public function __construct(public readonly string $id) {}
public function addItem(string $sku, int $qty, int $unitCents): void {
if ($qty < 1) { throw new DomainException('qty must be >= 1'); }
$this->items[] = new LineItem($sku, $qty, $unitCents);
}
public function total(): int {
return array_sum(array_map(fn(LineItem $i) => $i->subtotal(), $this->items));
}
}
$o = new Order('o1');
$o->addItem('A', 2, 500);
$o->addItem('B', 1, 300);
echo $o->total(), PHP_EOL; // 1300
Mereka bentuk agregat kecil
Kesilapan yang kerap berlaku ialah menjadikan agregat terlalu besar (sebuah Order yang turut memiliki keseluruhan graf Customer). Panduan umum:
- Pastikan agregat kecil; rujuk agregat lain menggunakan pengenal, bukan dengan menyimpan objek tersebut.
- Satu transaksi seharusnya mengubah suai satu agregat; selaraskan antara agregat menggunakan peristiwa domain.
- Invarian yang mesti sentiasa dipenuhi menentukan sempadan tersebut.
Rujuk melalui pengenal
Pesanan menyimpan objek nilai customerId, bukannya entiti Customer. Ini memastikan sempadan konsistensi kekal rapat dan mengelakkan pemuatan graf objek yang besar. Konsistensi merentas agregat menjadi konsistensi akhirnya, yang dikendalikan oleh peristiwa dan bukannya satu transaksi yang sangat besar.
<?php
final class CustomerId {
public function __construct(public readonly string $value) {}
}
final class Order {
public function __construct(
public readonly string $id,
public readonly CustomerId $customerId // reference, not object
) {}
}
$order = new Order('o1', new CustomerId('cus_99'));
echo $order->customerId->value, PHP_EOL;
Kontrak Repositori
Repositori memberikan gambaran seolah-olah terdapat koleksi dalam ingatan yang mengandungi akar agregat. Domain hanya bergantung pada antara muka; pelaksanaannya (Doctrine, PDO, dalam ingatan) berada dalam lapisan infrastruktur. Repositori berurusan dengan agregat lengkap, bukan baris separa.
<?php
interface OrderRepository {
public function ofId(string $id): ?Order;
public function save(Order $order): void;
public function nextIdentity(): string;
}
Pelaksanaan dalam ingatan
Repositori dalam ingatan amat berguna untuk ujian unit yang pantas dan tidak memerlukan pangkalan data. Oleh sebab domain bergantung pada antara muka, anda boleh menukar pelaksanaan dengan bebas (Pembalikan Kebergantungan dalam amalan).
<?php
interface OrderRepository {
public function ofId(string $id): ?object;
public function save(object $order): void;
public function nextIdentity(): string;
}
final class Order { public function __construct(public readonly string $id) {} }
final class InMemoryOrderRepository implements OrderRepository {
private array $store = [];
public function ofId(string $id): ?object { return $this->store[$id] ?? null; }
public function save(object $order): void { $this->store[$order->id] = $order; }
public function nextIdentity(): string { return 'o_' . bin2hex(random_bytes(4)); }
}
$repo = new InMemoryOrderRepository();
$repo->save(new Order('o1'));
var_dump($repo->ofId('o1') !== null);
Repositori bukan DAO
Repositori bukan DAO CRUD umum. Ia mendedahkan pertanyaan yang bermakna dari segi domain (findOverdueOrders()) dan membina semula agregat lengkap dengan invariannya yang terpelihara. Repositori sengaja menyembunyikan butiran SQL dan ORM supaya domain tidak bergantung pada penyimpanan. Elakkan daripada membocorkan pembina pertanyaan atau kaedah umum save($anyEntity) ke dalam domain.
Kilang untuk pembinaan kompleks
Apabila pembinaan agregat melibatkan logik sebenar — menjana identiti, memasang objek nilai dan menguatkuasakan invarian semasa penciptaan — pindahkan logik itu ke dalam kilang (kelas khusus atau pembina bernama statik). Ini memastikan pembina entiti kekal ringkas dan memusatkan peraturan penciptaan yang sah.
<?php
final class Order {
private function __construct(
public readonly string $id,
public readonly string $customerId
) {}
public static function place(string $customerId): self {
if ($customerId === '') { throw new DomainException('customer required'); }
return new self('o_' . bin2hex(random_bytes(4)), $customerId);
}
}
$order = Order::place('cus_1');
echo $order->id, PHP_EOL;
Cara semuanya bekerjasama
Aliran biasa dalam perkhidmatan aplikasi:
- Sebuah kilang (atau pembina bernama) mencipta agregat yang sah.
- Kaedah akar agregat menguatkuasakan invarian semasa digunakan.
- Sebuah repositori menyimpan dan kemudiannya membina semula keseluruhan agregat.
Perkhidmatan aplikasi menyelaraskan semua ini dalam satu transaksi bagi setiap agregat dan hanya bergantung pada antara muka.
Menguatkuasakan invarian seluruh agregat
Nilai sebenar akar ialah keupayaannya menguatkuasakan invarian yang merangkumi ahli-ahlinya. Di sini, pesanan menolak item baris jika item itu menyebabkan jumlah melebihi had kredit — peraturan yang tidak boleh dikuatkuasakan oleh satu LineItem sahaja. Oleh sebab semua perubahan mesti melalui akar, peraturan itu tidak boleh dipintas.
<?php
final class Order {
private array $items = [];
public function __construct(
public readonly string $id,
private int $creditLimitCents
) {}
public function addItem(int $cents): void {
if ($this->total() + $cents > $this->creditLimitCents) {
throw new DomainException('Exceeds credit limit');
}
$this->items[] = $cents;
}
public function total(): int { return array_sum($this->items); }
}
$o = new Order('o1', 1000);
$o->addItem(600);
try { $o->addItem(600); } catch (DomainException $e) { echo $e->getMessage(), PHP_EOL; }
echo $o->total(), PHP_EOL; // 600
Semakan Pantas
Reka bentuk agregat.
Rumusan
Anda telah mempelajari cara melindungi invarian dan menyimpan data dengan kemas. Agregat membentuk sempadan konsistensi dan transaksi, hanya diubah suai melalui akarnya serta dikekalkan kecil dengan merujuk agregat lain melalui pengenal. Repositori mempersembahkan akar agregat sebagai koleksi di sebalik antara muka domain, menyembunyikan ORM/SQL dan membolehkan pelaksanaan ujian dalam ingatan. Kilang memusatkan penciptaan kompleks yang menguatkuasakan invarian. Kesemuanya memastikan model domain anda konsisten dan tidak bergantung pada penyimpanan.
Pelajari PHP dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 49
- Pelajaran
- 195
Soalan Lazim
Adakah pelajaran “Agregat, Repositori dan Factory” percuma?
Ya — teks penuh “Agregat, Repositori dan Factory” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus PHP Academy, tingkat taraf kepada CoddyKit PRO. Kursus PHP Academy merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Agregat, Repositori dan Factory”?
Lindungi invarian dengan agregat dan kekalkannya secara kemas. Anda berlatih PHP Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan PHP Academy?
Tiada pengalaman terdahulu diperlukan. Pembelajaran PHP Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.
Berapa lamakah pelajaran “Agregat, Repositori dan Factory” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran PHP Academy ini?
Ya. Setiap pelajaran PHP Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Blok Binaan DDD: Entiti dan Objek Nilai
- Agregat, Repositori dan Factory
- Peristiwa Domain dan Perkhidmatan Domain
- Konteks Terbatas dan Pemetaan Konteks