Rumah > Artikel > pembangunan bahagian belakang > SOLID: Bahagian 4 - Prinsip Penyongsangan Ketergantungan
Tanggungjawab Tunggal (SRP), Terbuka/Tertutup (OCP), Penggantian Liskov, Pengasingan Antara Muka dan Penyongsangan Kebergantungan. Lima prinsip tangkas yang harus membimbing anda setiap kali anda menulis kod.
Adalah tidak adil untuk memberitahu anda bahawa mana-mana satu prinsip PADAT adalah lebih penting daripada yang lain. Walau bagaimanapun, mungkin tiada satu pun yang mempunyai kesan langsung dan mendalam pada kod anda selain Prinsip Inversi Ketergantungan, atau singkatannya DIP. Jika anda mendapati prinsip lain sukar untuk difahami atau digunakan, mulakan dengan prinsip ini dan kemudian gunakan prinsip yang selebihnya pada kod yang sudah mengikuti DIP.
A. Modul peringkat tinggi tidak boleh bergantung pada modul peringkat rendah. Kedua-duanya harus bergantung pada abstraksi.
B. Abstraksi tidak boleh bergantung pada butiran. Butirannya harus bergantung pada abstraksi.
Prinsip ini telah ditakrifkan oleh Robert C. Martin dalam bukunya "Agile Software Development, Principles, Patterns, and Practices" dan kemudiannya diterbitkan semula dalam versi C# dalam buku "Agile Principles, Patterns, and Practices in C#", yang Ia adalah prinsip terakhir daripada lima prinsip tangkas PADAT.
Sebelum kita mula coding, saya nak cerita dulu. Di Syneto, kami tidak sentiasa berhati-hati dengan kod kami. Beberapa tahun yang lalu kami tahu sangat sedikit dan walaupun kami telah mencuba yang terbaik, tidak semua projek adalah begitu baik. Kami telah melalui neraka dan kembali, dan kami telah belajar banyak melalui percubaan dan kesilapan.
Prinsip PADAT dan prinsip kesederhanaan seni bina Uncle Bob (Robert C. Martin) adalah pengubah permainan untuk kami dan mengubah cara kami mengekod dalam cara yang sukar untuk diterangkan. Ringkasnya, saya akan cuba menggambarkan beberapa keputusan seni bina utama yang dilaksanakan oleh DIP yang mempunyai kesan yang besar terhadap projek kami.
Kebanyakan projek web mengandungi tiga teknologi utama: HTML, PHP dan SQL. Tidak kira versi khusus aplikasi ini yang kita bincangkan atau jenis pelaksanaan SQL yang anda gunakan. Masalahnya ialah, maklumat dari borang HTML harus berakhir dalam pangkalan data entah bagaimana. Gam antara keduanya boleh disediakan oleh PHP.
Perkara yang paling penting ialah ketiga-tiga teknologi ini mewakili tiga lapisan seni bina yang berbeza dengan sangat baik: antara muka pengguna, logik perniagaan dan kegigihan. Kami akan membincangkan maksud lapisan ini kemudian. Sekarang, mari kita fokus pada beberapa penyelesaian pelik tetapi sering ditemui untuk menjadikan teknologi ini berfungsi bersama.
Banyak kali saya melihat projek menggunakan kod SQL dalam teg PHP di dalam fail HTML, atau kod PHP menggemakan halaman HTML dan mentafsir $_GET
或 $_POST
pembolehubah global secara langsung. Tetapi mengapa ini teruk?
Imej di atas mewakili versi asal yang kami huraikan dalam perenggan sebelumnya. Anak panah mewakili pelbagai kebergantungan dan kita boleh membuat kesimpulan bahawa pada dasarnya segala-galanya bergantung pada segala-galanya. Jika kami perlu membuat perubahan pada jadual pangkalan data, kami mungkin akan mengedit fail HTML. Atau, jika kita menukar medan dalam HTML, kita mungkin akhirnya menukar nama lajur dalam pernyataan SQL. Atau jika kita melihat corak kedua, jika HTML berubah, kemungkinan besar kita perlu mengubah suai PHP, atau dalam kes yang sangat buruk, apabila kita menjana semua kandungan HTML dari dalam fail PHP, kita pasti perlu menukar fail PHP untuk Mengubah suai kandungan HTML. Jadi, tidak syak lagi bahawa kebergantungan antara kelas dan modul adalah berliku-liku. Tetapi ia tidak berakhir di sana. Boleh menyimpan prosedur; kod PHP dalam jadual SQL.
Dalam skema di atas, pertanyaan terhadap pangkalan data SQL mengembalikan kod PHP yang dijana menggunakan data dalam jadual. Fungsi atau kelas PHP ini melaksanakan pertanyaan SQL lain yang mengembalikan kod PHP yang berbeza, dan gelung berterusan sehingga akhirnya semua maklumat diambil dan dikembalikan... mungkin kembali ke UI.
Saya tahu ini mungkin kedengaran keterlaluan bagi kebanyakan anda, tetapi jika anda tidak terlibat dalam projek yang dicipta dan dilaksanakan dengan cara ini, anda pasti akan melakukannya dalam kerjaya masa depan anda. Kebanyakan projek sedia ada, tanpa mengira bahasa pengaturcaraan, ditulis berdasarkan prinsip lama, oleh pengaturcara yang tidak peduli atau tidak tahu cara melakukannya dengan lebih baik. Jika anda membaca tutorial ini, kemungkinan besar anda telah mencapai tahap yang lebih tinggi. Anda bersedia, atau bersedia, untuk menghormati profesion anda, menerima keahlian anda dan melakukannya dengan lebih baik.
Alternatifnya ialah mengulangi kesilapan mereka yang terdahulu daripada anda dan menanggung akibatnya. Di Syneto, apabila salah satu projek kami mencapai keadaan hampir tidak dapat diselenggara kerana seni bina lama dan saling bergantung dan pada asasnya kami terpaksa meninggalkannya untuk selamanya, kami memutuskan untuk tidak mengikuti laluan itu lagi. Sejak itu kami telah berusaha untuk mempunyai seni bina yang bersih, dengan betul menghormati prinsip SOLID dan yang paling penting prinsip penyongsangan kebergantungan.
Keajaiban seni bina ini ialah bagaimana kebergantungan ditunjukkan:
Mengaplikasikan Dependency Inversion Principle (DIP) pada peringkat seni bina adalah sangat mudah jika anda menghormati corak reka bentuk tangkas klasik. Ia juga mudah malah menyeronokkan untuk berlatih dan memberi contoh dalam logik perniagaan. Kami akan membayangkan aplikasi pembaca e-buku.
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new PDFReader($b); $this->assertRegExp('/pdf book/', $r->read()); } } class PDFReader { private $book; function __construct(PDFBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook { function read() { return "reading a pdf book."; } }
Kami mula membangunkan e-pembaca menjadi pembaca PDF. Setakat ini, begitu baik. Kami mempunyai semakan regex untuk mengesahkan ini menggunakan bahagian utama rentetan yang dikembalikan oleh kaedah PDFBook
的 PDFReader
类。读者上的 read()
函数委托给本书的 read()
方法。我们只是通过在 PDFBook
的 reader()
.
Sila ingat ini hanyalah contoh. Kami tidak akan melaksanakan logik bacaan untuk fail PDF atau format fail lain. Itulah sebabnya ujian kami hanya akan menyemak beberapa rentetan asas. Jika kami menulis aplikasi sebenar, satu-satunya perbezaan adalah bagaimana kami menguji format fail yang berbeza. Struktur pergantungan sangat serupa dengan contoh kami.
拥有一个使用 PDF 书籍的 PDF 阅读器对于有限的应用程序来说可能是一个合理的解决方案。如果我们的范围是编写一个 PDF 阅读器,仅此而已,那么它实际上是一个可以接受的解决方案。但我们想编写一个通用的电子书阅读器,支持多种格式,其中我们第一个实现的版本是 PDF。让我们重命名我们的读者类。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } } class EBookReader { private $book; function __construct(PDFBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook { function read() { return "reading a pdf book."; } }
重命名没有功能上的反作用。测试仍在通过。
测试于下午 1:04 开始...
PHPUnit 3.7.28 由 Sebastian Bergmann 编写。
时间:13 毫秒,内存:2.50Mb
好的(1 个测试,1 个断言)
进程已完成,退出代码为 0
但它具有严重的设计效果。
我们的读者变得更加抽象。更一般。我们有一个通用的 EBookReader
,它使用非常具体的书籍类型 PDFBook
。抽象取决于细节。我们的书是 PDF 类型这一事实应该只是一个细节,任何人都不应该依赖它。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } } interface EBook { function read(); } class EBookReader { private $book; function __construct(EBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook implements EBook{ function read() { return "reading a pdf book."; } }
反转依赖关系最常见、最常用的解决方案是在我们的设计中引入一个更抽象的模块。 “OOP 中最抽象的元素是接口。因此,任何其他类都可以依赖于接口并且仍然遵循 DIP”。
我们为读者创建了一个界面。该接口名为 EBook
,代表 EBookReader
的需求。这是尊重接口隔离原则 (ISP) 的直接结果,该原则提倡接口应反映客户端需求的理念。接口属于客户端,因此它们的命名反映了客户端需要的类型和对象,并且它们将包含客户端想要使用的方法。 EBookReader
使用 EBooks
并拥有 read()
方法是很自然的。
我们现在有两个依赖项,而不是单个依赖项。
EBookReader
指向 EBook
接口,并且它是类型用法。 EBookReader
使用 EBooks
。PDFBook
指向相同的 EBook
接口,但它是类型实现。 PDFBook
只是 EBook
的一种特殊形式,因此实现了该接口来满足客户的需求。不出所料,该解决方案还允许我们将不同类型的电子书插入阅读器。所有这些书籍的唯一条件是满足 EBook
接口并实现它。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } function testItCanReadAMobiBook() { $b = new MobiBook(); $r = new EBookReader($b); $this->assertRegExp('/mobi book/', $r->read()); } } interface EBook { function read(); } class EBookReader { private $book; function __construct(EBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook implements EBook { function read() { return "reading a pdf book."; } } class MobiBook implements EBook { function read() { return "reading a mobi book."; } }
这又将我们引向开闭原则,并且圆圈是闭合的。
依赖倒置原则是引导或帮助我们尊重所有其他原则的原则。尊重 DIP 将:
就是这样。我们完了。所有有关 SOLID 原理的教程均已完成。对我个人来说,发现这些原则并在实施项目时牢记它们是一个巨大的变化。我完全改变了我对设计和架构的思考方式,我可以说从那时起我从事的所有项目都变得更加容易管理和理解。
我认为 SOLID 原则是面向对象设计最基本的概念之一。这些概念必须指导我们使我们的代码变得更好,并使我们作为程序员的生活变得更加轻松。设计良好的代码更容易让程序员理解。计算机很聪明,无论代码多么复杂,它们都可以理解。另一方面,人类能够在活跃、专注的头脑中保存的事物数量有限。更具体地说,此类事物的数量是神奇数字七、正负二。
Kita harus berusaha untuk menyusun kod kita di sekitar nombor ini, dan terdapat beberapa teknik yang boleh membantu kita melakukan ini. Fungsi hendaklah maksimum empat baris panjang (lima baris termasuk garis definisi) supaya ia boleh muat di kepala kita pada masa yang sama. Kedalaman lekukan tidak melebihi lima lapisan. Kelas dengan tidak lebih daripada sembilan kaedah. Biasanya lima hingga sembilan kelas corak reka bentuk digunakan. Reka bentuk peringkat tinggi kami dalam corak di atas menggunakan empat hingga lima konsep. Terdapat lima prinsip SOLID, setiap satu memerlukan antara lima dan sembilan subkonsep/modul/kelas untuk dicontohi. Saiz yang sesuai untuk pasukan pengaturcaraan ialah lima hingga sembilan orang. Bilangan pasukan yang ideal dalam sesebuah syarikat ialah lima hingga sembilan.
Seperti yang anda lihat, nombor ajaib tujuh, tambah atau tolak dua, ada di sekeliling kita, jadi mengapa kod anda perlu berbeza?
Atas ialah kandungan terperinci SOLID: Bahagian 4 - Prinsip Penyongsangan Ketergantungan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!