Prinsip SOLID Kelas SOLID
4. I: Prinsip Pengasingan Antara Muka (ISP)
5 D: Prinsip Inversi Ketergantungan (DIP)
SOLID- S: Prinsip Tanggungjawab Tunggal (SRP)
< /li>
- O: Prinsip Tertutup (OCP)
- L: Prinsip Penggantian Liskov (LSP)
li>
- I: Prinsip Pemisahan Antara Muka (ISP)
SOLID
是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则S: 单一职责原则 (SRP)
O: 开闭原则 (OCP)
L: 里氏替换原则 (LSP)
I: 接口隔离原则 (ISP)
D: 依赖倒置原则 (DIP)
1. 单一职责原则
Single Responsibility Principle (SRP)
正如在Clean Code所述,"修改一个类应该只为一个理由"。 人们总是易于用一堆方法塞满一个类,如同我们只能在飞机上 只能携带一个行李箱(把所有的东西都塞到箱子里)。这样做 的问题是:从概念上这样的类不是高内聚的,并且留下了很多 理由去修改它。将你需要修改类的次数降低到最小很重要。 这是因为,当有很多方法在类中时,修改其中一处,你很难知 晓在代码库中哪些依赖的模块会被影响到。
坏:
class UserSettings { private $user; public function __construct(User $user) { $this->user = $user; } public function changeSettings(array $settings): void { if ($this->verifyCredentials()) { // ... } } private function verifyCredentials(): bool { // ... } }
好:
class UserAuth { private $user; public function __construct(User $user) { $this->user = $user; } public function verifyCredentials(): bool { // ... } } class UserSettings { private $user; private $auth; public function __construct(User $user) { $this->user = $user; $this->auth = new UserAuth($user); } public function changeSettings(array $settings): void { if ($this->auth->verifyCredentials()) { // ... } } }
2. 开闭原则
Open/Closed Principle (OCP)
正如Bertrand Meyer所述,"软件的工件(
classes, modules, functions
等) 应该对扩展开放,对修改关闭。" 然而这句话意味着什么呢?这个原则大体上表示你 应该允许在不改变已有代码的情况下增加新的功能坏:
abstract class Adapter { protected $name; public function getName(): string { return $this->name; } } class AjaxAdapter extends Adapter { public function __construct() { parent::__construct(); $this->name = 'ajaxAdapter'; } } class NodeAdapter extends Adapter { public function __construct() { parent::__construct(); $this->name = 'nodeAdapter'; } } class HttpRequester { private $adapter; public function __construct(Adapter $adapter) { $this->adapter = $adapter; } public function fetch(string $url): Promise { $adapterName = $this->adapter->getName(); if ($adapterName === 'ajaxAdapter') { return $this->makeAjaxCall($url); } elseif ($adapterName === 'httpNodeAdapter') { return $this->makeHttpCall($url); } } private function makeAjaxCall(string $url): Promise { // request and return promise } private function makeHttpCall(string $url): Promise { // request and return promise } }
好:
interface Adapter { public function request(string $url): Promise; } class AjaxAdapter implements Adapter { public function request(string $url): Promise { // request and return promise } } class NodeAdapter implements Adapter { public function request(string $url): Promise { // request and return promise } } class HttpRequester { private $adapter; public function __construct(Adapter $adapter) { $this->adapter = $adapter; } public function fetch(string $url): Promise { return $this->adapter->request($url); } }
3. 里氏替换原则
Liskov Substitution Principle (LSP)
D: Prinsip Inversi Ketergantungan (DIP)
class Rectangle { protected $width = 0; protected $height = 0; public function setWidth(int $width): void { $this->width = $width; } public function setHeight(int $height): void { $this->height = $height; } public function getArea(): int { return $this->width * $this->height; } } class Square extends Rectangle { public function setWidth(int $width): void { $this->width = $this->height = $width; } public function setHeight(int $height): void { $this->width = $this->height = $height; } } function printArea(Rectangle $rectangle): void { $rectangle->setWidth(4); $rectangle->setHeight(5); // BAD: Will return 25 for Square. Should be 20. echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; } $rectangles = [new Rectangle(), new Square()]; foreach ($rectangles as $rectangle) { printArea($rectangle); }🎜Baik:🎜
interface Shape { public function getArea(): int; } class Rectangle implements Shape { private $width = 0; private $height = 0; public function __construct(int $width, int $height) { $this->width = $width; $this->height = $height; } public function getArea(): int { return $this->width * $this->height; } } class Square implements Shape { private $length = 0; public function __construct(int $length) { $this->length = $length; } public function getArea(): int { return $this->length ** 2; } } function printArea(Shape $shape): void { echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL; } $shapes = [new Rectangle(4, 5), new Square(5)]; foreach ($shapes as $shape) { printArea($shape); }🎜🎜2. Prinsip Terbuka/Tertutup🎜🎜🎜
interface Employee { public function work(): void; public function eat(): void; } class HumanEmployee implements Employee { public function work(): void { // ....working } public function eat(): void { // ...... eating in lunch break } } class RobotEmployee implements Employee { public function work(): void { //.... working much more } public function eat(): void { //.... robot can't eat, but it must implement this method } }🎜Baik:🎜
interface Workable { public function work(): void; } interface Feedable { public function eat(): void; } interface Employee extends Feedable, Workable { } class HumanEmployee implements Employee { public function work(): void { // ....working } public function eat(): void { //.... eating in lunch break } } // robot can only work class RobotEmployee implements Workable { public function work(): void { // ....working } }🎜 🎜🎜< a name=" 3">🎜3. Prinsip Penggantian Liskov🎜🎜
Penjelasan terbaik tentang konsep ini ialah: jika anda mempunyai kelas induk dan kelas anak, kelas induk dan kelas anak boleh ditukar tanpa mengubah ketepatan hasil asal. Ini masih kedengaran sedikit mengelirukan, jadi mari kita lihat contoh segi empat tepat klasik. Secara matematik, segi empat sama ialah segi empat tepat, tetapi itu tidak benar apabila model anda menggunakan perhubungan "is-a" melalui pewarisan.
Buruk:
class Employee { public function work(): void { // ....working } } class Robot extends Employee { public function work(): void { //.... working much more } } class Manager { private $employee; public function __construct(Employee $employee) { $this->employee = $employee; } public function manage(): void { $this->employee->work(); } }
Baik:
Adalah lebih baik untuk merawat kedua-dua jenis quad ini secara berasingan dan menggantikannya dengan subjenis yang lebih umum yang sesuai dengan kedua-dua jenis.
Walaupun segi empat sama dan segi empat tepat kelihatan serupa, ia berbeza. Segi empat sama lebih dekat dengan rombus, manakala segi empat tepat lebih dekat dengan segi empat selari. Tetapi mereka bukan subjenis. Walaupun serupa, segi empat sama, segi empat tepat, rombus dan segi empat selari adalah semua bentuk yang berbeza dengan sifatnya sendiri.
interface Employee { public function work(): void; } class Human implements Employee { public function work(): void { // ....working } } class Robot implements Employee { public function work(): void { //.... working much more } } class Manager { private $employee; public function __construct(Employee $employee) { $this->employee = $employee; } public function manage(): void { $this->employee->work(); } }
4. Prinsip Pengasingan Antara Muka
Interface Segregation Principle (ISP)
接口隔离原则表示:"调用方不应该被强制依赖于他不需要的接口"
有一个清晰的例子来说明示范这条原则。当一个类需要一个大量的设置项, 为了方便不会要求调用方去设置大量的选项,因为在通常他们不需要所有的 设置项。使设置项可选有助于我们避免产生"胖接口"
坏:
rrreee好:
不是每一个工人都是雇员,但是每一个雇员都是一个工人
rrreee5. 依赖倒置原则
Dependency Inversion Principle (DIP)
Ya Contoh yang jelas menunjukkan prinsip ini. Apabila kelas memerlukan sejumlah besar tetapan, adalah mudah untuk tidak memerlukan pemanggil untuk menetapkan sejumlah besar pilihan, kerana biasanya mereka tidak memerlukan semua tetapan. Menjadikan tetapan sebagai pilihan membantu kita mengelakkan "antara muka gemuk"
Buruk:
rrreee
Baik:
Bukan setiap pekerja adalah pekerja, tetapi setiap pekerja adalah pekerjarrreee< a name="5"> 5. Prinsip Penyongsangan Ketergantungan