OOP (Pemrograman Berorientasi Objek) telah menjadi bagian integral dari pengembangan banyak proyek modern, tetapi meskipun populer, paradigma ini jauh dari satu-satunya. Jika Anda sudah tahu cara bekerja dengan paradigma lain dan ingin membiasakan diri Anda dengan okultisme OOP, maka di depan Anda ada gambar dan animasi yang agak panjang dan dua megabita. Transformer akan berfungsi sebagai contoh.

Hal pertama yang harus dijawab adalah mengapa? Ideologi berorientasi objek dikembangkan sebagai upaya untuk menghubungkan perilaku entitas dengan data dan proyek objek dunia nyata dan proses bisnis ke dalam kode program. Diperkirakan bahwa kode semacam itu lebih mudah dibaca dan dipahami oleh seseorang, karena sudah lazim bagi orang untuk memandang dunia sekitar sebagai banyak objek yang saling berinteraksi, yang dapat menerima klasifikasi tertentu. Apakah mungkin bagi para ideolog untuk mencapai tujuan, sulit untuk menjawab dengan tegas, tetapi secara de facto kami memiliki banyak proyek di mana programmer akan membutuhkan OOP.
Anda seharusnya tidak berpikir bahwa OOP entah bagaimana akan secara ajaib mempercepat penulisan program, dan mengharapkan situasi di mana penduduk Villaribo telah meluncurkan proyek OOP untuk bekerja, dan penduduk Villabaggio masih mencuci kode spageti yang tebal. Dalam kebanyakan kasus, ini tidak demikian, dan waktu disimpan bukan pada tahap pengembangan, tetapi pada tahap dukungan (ekspansi, modifikasi, debugging dan pengujian), yaitu, dalam jangka panjang. Jika Anda perlu menulis skrip satu kali yang tidak memerlukan dukungan berikutnya, maka OOP dalam tugas ini kemungkinan besar tidak berguna. Namun, bagian penting dari siklus hidup sebagian besar proyek modern adalah tepatnya dukungan dan ekspansi. Memiliki OOP sendiri tidak membuat arsitektur Anda sempurna, dan sebaliknya dapat menyebabkan komplikasi yang tidak perlu.
Terkadang Anda mungkin menghadapi kritik terhadap kinerja program OOP. Memang benar bahwa ada sedikit overhead, tetapi begitu tidak signifikan sehingga dalam kebanyakan kasus dapat diabaikan demi keuntungan. Namun demikian, dalam kemacetan di mana jutaan objek per detik harus dibuat atau diproses dalam satu utas, ada baiknya setidaknya merevisi kebutuhan OOP, karena bahkan biaya minimum dalam jumlah seperti itu dapat secara signifikan mempengaruhi kinerja. Profiling akan membantu Anda menangkap perbedaan dan membuat keputusan. Dalam kasus lain, katakanlah, di mana bagian terbesar dari kecepatan terletak pada IO, pengabaian objek akan menjadi optimasi prematur.
Sesuai sifatnya, pemrograman berorientasi objek paling baik dijelaskan dengan contoh-contoh. Seperti yang dijanjikan, pasien kami akan menjadi transformer. Saya bukan transformator, dan saya belum membaca komik, oleh karena itu, dalam contoh saya akan dibimbing oleh Wikipedia dan fantasi.
Kelas dan Objek
Penyimpangan liris segera: pendekatan berorientasi objek dimungkinkan tanpa kelas, tetapi kami akan mempertimbangkan, saya minta maaf atas permainan kata-kata, skema klasik, di mana kelas adalah segalanya bagi kami.
Penjelasan paling sederhana: kelas adalah gambar transformator, dan instance kelas ini adalah transformer spesifik, misalnya, Optimus Prime atau Oleg. Dan meskipun mereka berkumpul menurut satu gambar, mereka dapat berjalan, mengubah dan menembak dengan cara yang sama, mereka berdua memiliki kondisi unik mereka sendiri. Status adalah serangkaian sifat yang berubah. Oleh karena itu, dalam dua objek berbeda dari kelas yang sama, kita dapat mengamati nama, umur, lokasi, tingkat muatan, jumlah amunisi, dan sebagainya yang berbeda. Keberadaan properti ini dan tipenya dijelaskan di dalam kelas.
Dengan demikian, kelas adalah deskripsi properti dan perilaku apa yang akan dimiliki suatu objek. Dan sebuah objek adalah instance dengan keadaan sendiri dari properti ini.
Kami mengatakan "properti dan perilaku", tetapi entah bagaimana itu terdengar abstrak dan tidak dapat dipahami. Akan lebih akrab bagi seorang programmer terdengar seperti ini: "variabel dan fungsi". Bahkan, "properti" adalah variabel biasa yang sama, mereka hanya atribut dari beberapa objek (mereka disebut bidang objek). Demikian pula, "perilaku" adalah fungsi dari suatu objek (mereka disebut metode), yang juga merupakan atribut dari objek. Perbedaan antara metode objek dan fungsi biasa hanya bahwa metode memiliki akses ke keadaannya sendiri melalui bidang.
Secara total, kami memiliki metode dan properti yang merupakan atribut. Bagaimana cara bekerja dengan atribut? Dalam kebanyakan PL, operator referensi atribut adalah intinya (kecuali untuk PHP dan Perl). Itu terlihat seperti ini (pseudo-code):
Dalam gambar saya akan menggunakan notasi berikut:

Saya tidak menggunakan diagram UML, menganggapnya tidak cukup visual, meskipun lebih fleksibel.
Animasi nomor 1Apa yang kita lihat dari kode?
1.
ini adalah variabel lokal khusus (metode dalam) yang memungkinkan objek mengakses atributnya sendiri dari metodenya. Saya menarik perhatian Anda bahwa hanya untuk Anda sendiri, yaitu, ketika transformator memanggil metode sendiri, atau mengubah kondisinya sendiri. Jika panggilan terlihat seperti
optimus.x dari
luar , kemudian dari dalam, jika Optimus ingin merujuk ke bidangnya x sendiri, dalam metodenya panggilan akan terlihat seperti
ini.x , yaitu, "
Saya (Optimus) merujuk ke atribut saya x ". Di sebagian besar bahasa, variabel ini disebut ini, tetapi ada pengecualian (mis. Sendiri)
2.
konstruktor adalah metode khusus yang secara otomatis dipanggil ketika suatu objek dibuat. Konstruktor dapat menerima argumen apa pun, seperti metode lainnya. Dalam setiap bahasa, sebuah konstruktor ditandai dengan namanya. Di suatu tempat ini adalah nama-nama yang khusus disediakan seperti __construct atau __init__, dan di suatu tempat nama konstruktor harus cocok dengan nama kelas. Tujuan konstruktor adalah untuk menginisialisasi objek, mengisi bidang yang diperlukan.
3.
new adalah kata kunci yang harus digunakan untuk membuat instance kelas baru. Pada titik ini, sebuah objek dibuat dan konstruktor dipanggil. Dalam contoh kita, 0 dilewatkan ke konstruktor sebagai posisi awal transformator (ini adalah inisialisasi di atas). Kata kunci baru hilang dalam beberapa bahasa, dan konstruktor dipanggil secara otomatis ketika mencoba memanggil kelas sebagai fungsi, misalnya: Transformer ().
4. Konstruktor dan menjalankan
metode bekerja dengan keadaan internal, tetapi dalam semua hal lainnya tidak berbeda dari fungsi biasa . Bahkan sintaksis dari deklarasi cocok.
5. Kelas mungkin memiliki metode yang tidak memerlukan status dan, sebagai akibatnya, membuat objek. Dalam hal ini, metode ini dibuat
statis .
Srp
(Prinsip Tanggung Jawab Tunggal / Prinsip
SOLID Pertama). Anda mungkin sudah terbiasa dengan itu dari paradigma lain: "satu fungsi harus melakukan hanya satu tindakan yang selesai". Prinsip ini juga berlaku untuk kelas: "Satu kelas harus bertanggung jawab atas satu tugas." Sayangnya dengan kelas, lebih sulit untuk menentukan garis yang harus dilintasi sehingga prinsip dilanggar.
Ada upaya untuk memformalkan prinsip ini dengan menggambarkan tujuan kelas dengan satu kalimat tanpa serikat, tetapi ini adalah teknik yang sangat kontroversial, jadi percayalah pada intuisi Anda dan jangan terburu-buru ke ekstrem. Anda tidak perlu membuat pisau Swiss dari kelas, tetapi menghasilkan sejuta kelas dengan satu metode di dalamnya juga bodoh.
Asosiasi
Secara tradisional, di bidang objek tidak hanya variabel biasa dari tipe standar dapat disimpan, tetapi juga objek lain. Dan benda-benda ini pada gilirannya dapat menyimpan beberapa benda lain dan seterusnya, membentuk pohon (kadang-kadang grafik) benda. Hubungan ini disebut asosiasi.
Misalkan trafo kita dilengkapi dengan pistol. Meski tidak, lebih baik dengan dua senjata. Di masing-masing tangan. Senjatanya sama (mereka milik kelas yang sama, atau, jika Anda suka, dibuat menurut satu gambar), keduanya dapat menembak dan memuat ulang secara merata, tetapi masing-masing memiliki penyimpanan amunisi sendiri (negara bagian). Bagaimana sekarang menggambarkannya dalam OOP? Menurut asosiasi:
class Gun(){
Animasi nomor 2this.gun_left.fire () dan this.gun_right.fire () adalah panggilan ke objek anak yang juga terjadi melalui titik-titik. Pada titik pertama, kita beralih ke atribut diri kita sendiri (this.gun_right), mendapatkan objek gun, dan pada poin kedua, kita beralih ke metode objek gun (this.gun_right.fire ()).
Intinya: robot itu dibuat, senjata dinas dikeluarkan, sekarang kita akan mencari tahu apa yang terjadi di sini. Dalam kode ini, satu objek telah menjadi bagian integral dari objek lain. Ini asosiasi. Pada gilirannya, ada dua jenis:
1.
Komposisi - kasus ketika, di pabrik transformator, mengumpulkan Optimus, kedua senjata ditempelkan erat ke tangannya dengan paku, dan setelah kematian Optimus, senjata mati bersamanya. Dengan kata lain, siklus hidup anak sama dengan siklus hidup orang tua.
2.
Agregasi - kasus ketika senjata dikeluarkan sebagai senjata di tangannya, dan setelah kematian Optimus, senjata ini dapat diambil oleh rekannya Oleg, dan kemudian dibawa ke tangannya sendiri, atau diserahkan ke pegadaian. Artinya, siklus hidup objek anak tidak tergantung pada siklus hidup orang tua, dan dapat digunakan oleh objek lain.
Gereja OOP ortodoks memberitakan kepada kita trinitas mendasar -
enkapsulasi, polimorfisme, dan warisan , yang menjadi dasar seluruh pendekatan berorientasi objek. Mari kita mengurutkannya.

Warisan
Warisan adalah suatu mekanisme sistem yang memungkinkan, betapapun paradoksnya mungkin terdengar, mewarisi sifat-sifat dan perilaku kelas-kelas lain oleh beberapa kelas untuk perluasan atau modifikasi lebih lanjut.
Bagaimana jika, kami tidak ingin memberi cap pada transformator yang sama, tetapi ingin membuat kerangka yang sama, tetapi dengan body kit yang berbeda? OOP memungkinkan kita melakukan lelucon seperti itu dengan membagi logika menjadi persamaan dan perbedaan, diikuti dengan penghapusan persamaan di kelas induk, dan perbedaan dalam kelas turunan. Seperti apa bentuknya?
Optimus Prime dan Megatron keduanya adalah transformator, tetapi yang satu adalah Autobot dan yang lainnya adalah Decepticon. Misalkan perbedaan antara Autobots dan Decepticons hanya akan terdiri dari kenyataan bahwa Autobots ditransformasikan menjadi mobil, dan Decepticons - menjadi penerbangan. Semua properti dan perilaku lainnya tidak akan membuat perbedaan. Dalam hal ini, sistem pewarisan dapat dirancang sebagai berikut: fitur-fitur umum (berlari, menembak) akan dijelaskan dalam kelas dasar Transformer, dan perbedaan (transformasi) di dua kelas tambahan Autobot dan Decepticon.
class Transformer(){
Animasi nomor 3Contoh ini menggambarkan bagaimana pewarisan menjadi salah satu cara untuk mendeduplikasi kode (
prinsip KERING ) menggunakan kelas induk, dan pada saat yang sama memberikan peluang untuk mutasi di kelas turunan.
Kelebihan
Jika Anda mengganti metode yang ada di kelas induk di kelas induk, overload akan berfungsi. Ini memungkinkan kami untuk tidak menambah perilaku kelas induk, tetapi untuk memodifikasinya. Pada saat memanggil metode atau mengakses bidang objek, pencarian atribut terjadi dari turunan ke akar - induknya. Yaitu, jika metode api () dipanggil pada autobot, metode pertama kali dicari di kelas turunan - Autobot, dan karena tidak ada, pencarian naik satu langkah lebih tinggi - ke kelas Transformer, di mana ia akan dideteksi dan dipanggil.
Penggunaan yang tidak pantas
Sangat mengherankan bahwa hierarki warisan yang sangat dalam dapat menyebabkan efek sebaliknya - komplikasi ketika mencoba untuk mencari tahu siapa yang diwarisi dari siapa, dan metode apa yang disebut dalam hal ini. Selain itu, tidak semua persyaratan arsitektur dapat diimplementasikan menggunakan pewarisan. Karena itu, pewarisan harus diterapkan tanpa fanatisme. Ada rekomendasi yang menyerukan komposisi yang lebih disukai daripada warisan, jika sesuai. Setiap kritik terhadap warisan yang saya temui diperkuat oleh contoh-contoh yang tidak berhasil ketika warisan digunakan sebagai
palu emas . Tetapi ini tidak berarti bahwa warisan pada prinsipnya selalu berbahaya. Narcologist saya mengatakan bahwa langkah pertama adalah mengakui bahwa Anda bergantung pada warisan.
Ketika menggambarkan hubungan dua entitas, bagaimana mungkin menentukan kapan pewarisan sesuai dan kapan komposisinya tepat? Anda dapat menggunakan lembar contekan yang populer: tanyakan pada diri Anda,
entitas A adalah entitas B ? Jika demikian, maka kemungkinan besar warisan adalah tepat. Jika
entitas A adalah bagian dari entitas B , maka pilihan kita adalah komposisi.
Sehubungan dengan situasi kita, akan terdengar seperti ini:
- Apakah Autobot Transformer? Ya, maka kami memilih warisan.
- Apakah pistol bagian dari Transformer? Ya, itu artinya komposisi.
Untuk swa-uji, coba kombinasi terbalik, Anda mendapat sampah. Lembar cheat ini membantu dalam banyak kasus, tetapi ada faktor-faktor lain yang harus Anda andalkan ketika memilih antara komposisi dan warisan. Selain itu, metode ini dapat dikombinasikan untuk menyelesaikan berbagai jenis masalah.
Warisan bersifat Statis
Perbedaan penting lainnya antara pewarisan dan komposisi adalah bahwa pewarisan sifatnya statis dan membangun hubungan kelas hanya pada tahap interpretasi / kompilasi. Komposisi, seperti yang kita lihat dalam contoh, memungkinkan Anda untuk mengubah hubungan entitas dengan cepat saat runtime - kadang-kadang ini sangat penting, jadi Anda perlu mengingat ini saat memilih hubungan (kecuali tentu saja ada keinginan untuk menggunakan
metaprogramming ).
Warisan berganda
Kami memeriksa situasi di mana dua kelas diwarisi dari keturunan bersama. Tetapi dalam beberapa bahasa Anda dapat melakukan yang sebaliknya - mewarisi satu kelas dari dua orang tua atau lebih, menggabungkan sifat dan perilaku mereka. Kemampuan untuk mewarisi dari beberapa kelas bukan satu adalah warisan ganda.

Secara umum, di kalangan Illuminati ada pendapat bahwa pewarisan berganda adalah dosa, ia membawa
masalah berbentuk berlian dan kebingungan dengan para desainer. Selain itu, tugas yang dapat diselesaikan dengan pewarisan berganda dapat diselesaikan dengan mekanisme lain, misalnya mekanisme antarmuka (yang juga akan kita bicarakan). Tetapi dalam keadilan, harus dicatat bahwa pewarisan berganda nyaman digunakan untuk penerapan
pengotor .
Kelas abstrak
Selain kelas biasa, bahasa abstrak ada di beberapa bahasa. Mereka berbeda dari kelas biasa karena Anda tidak dapat membuat objek dari kelas semacam itu. Mengapa kita membutuhkan kelas seperti itu, pembaca akan bertanya? Diperlukan agar keturunan dapat diwarisi darinya - kelas biasa yang objeknya sudah dapat dibuat.
Kelas abstrak, bersama dengan metode biasa, berisi metode abstrak tanpa implementasi (dengan tanda tangan, tetapi tanpa kode), yang harus diimplementasikan oleh programmer yang berencana membuat kelas turunan. Kelas abstrak tidak diperlukan, tetapi mereka membantu untuk membuat kontrak yang membutuhkan implementasi dari serangkaian metode tertentu untuk melindungi seorang programmer dengan memori yang buruk dari kesalahan implementasi.
Polimorfisme
Polimorfisme adalah properti sistem yang memungkinkan Anda memiliki banyak implementasi satu antarmuka. Tidak ada yang jelas. Mari kita beralih ke transformer.
Misalkan kita memiliki tiga transformer: Optimus, Megatron, dan Oleg. Transformer adalah pertempuran, sehingga mereka memiliki metode serangan (). Pemain, dengan menekan tombol “fight” pada joystick-nya, memberi tahu game untuk memanggil metode attack () pada transformator yang dimainkan pemain. Tetapi karena transformernya berbeda, dan permainannya menarik, masing-masing dari mereka akan menyerang dengan cara tertentu. Katakanlah Optimus adalah objek dari kelas Autobot, dan Autobots dilengkapi dengan meriam dengan hulu ledak plutonium (ya, penggemar transformer tidak marah). Megatron adalah Decepticon, dan menembak dari senjata plasma. Oleg adalah pemain bass, dan dia memanggilnya nama. Dan apa gunanya?
Penggunaan polimorfisme dalam contoh ini adalah bahwa kode permainan tidak tahu apa-apa tentang implementasi permintaannya, siapa yang harus menyerang caranya, tugasnya hanya memanggil metode serangan (), yang tanda tangannya sama untuk semua kelas karakter. Ini memungkinkan Anda untuk menambahkan kelas karakter baru, atau mengubah metode yang ada tanpa mengubah kode game. Ini nyaman.
Enkapsulasi
Enkapsulasi adalah kontrol akses ke bidang dan metode suatu objek. Kontrol akses menyiratkan tidak hanya mungkin / tidak penting, tetapi juga berbagai validasi, memuat, perhitungan, dan perilaku dinamis lainnya.
Dalam banyak bahasa, enkripsi data adalah bagian dari enkapsulasi. Untuk ini, ada pengubah akses (kami gambarkan mereka yang ada di hampir semua bahasa OOP):
- publi - siapa pun dapat mengakses atribut
- metode pribadi - hanya dari kelas ini dapat mengakses atribut
- dilindungi - sama seperti pribadi, hanya ahli waris kelas yang mendapatkan akses, termasuk
class Transformer(){ public function constructor(){ } protected function setup(){ } private function dance(){ } }
Bagaimana memilih pengubah akses? Dalam kasus paling sederhana seperti ini: jika metode ini harus dapat diakses oleh kode eksternal, pilih publik. Kalau tidak, pribadi. Jika ada warisan, maka dilindungi mungkin diperlukan jika metode ini tidak boleh disebut eksternal, tetapi harus dipanggil oleh keturunan.
Accessor (getter dan setter)
Getters dan setters adalah metode yang tugasnya mengontrol akses ke bidang. Sang pengambil rajin membaca dan mengembalikan nilai field, dan setter, sebaliknya, mengambil nilai sebagai argumen dan menuliskannya ke field. Ini memungkinkan untuk memberikan metode semacam itu dengan perawatan tambahan. Misalnya, seorang penyetel, saat menulis nilai ke bidang objek, dapat memeriksa jenisnya atau apakah nilainya dalam kisaran nilai yang valid (validasi). Di rajin rajin, Anda dapat menambahkan inisialisasi malas atau caching jika nilai aktual sebenarnya terletak di database. Ada banyak aplikasi.
Beberapa bahasa memiliki gula sintaksis yang memungkinkan pengakses seperti itu untuk disamarkan sebagai properti, yang membuat akses transparan ke kode eksternal, yang tidak menduga bahwa itu tidak bekerja dengan bidang, tetapi dengan metode yang mengeksekusi query SQL atau membaca dari file di bawah tenda. Beginilah cara abstraksi dan transparansi dicapai.
Antarmuka
Tugas antarmuka adalah untuk mengurangi tingkat ketergantungan entitas satu sama lain, menambahkan lebih banyak abstraksi.
Tidak semua bahasa memiliki mekanisme ini, tetapi dalam bahasa OOP dengan mengetik statis tanpa mereka akan sangat buruk. Di atas, kami mempertimbangkan kelas abstrak, menyentuh pada topik kontrak yang berkewajiban mengimplementasikan beberapa metode abstrak. Jadi antarmuka terlihat sangat mirip kelas abstrak, tetapi ini bukan kelas, tetapi hanya tiruan dengan enumerasi metode abstrak (tanpa implementasi). Dengan kata lain, antarmuka bersifat deklaratif, yaitu, kontrak bersih tanpa sedikit kode.
Biasanya, bahasa yang memiliki antarmuka tidak memiliki banyak kelas pewarisan, tetapi ada banyak antarmuka yang berbeda. Ini memungkinkan kelas untuk membuat daftar antarmuka yang harus diimplementasikan.
Kelas dengan antarmuka terdiri dari hubungan banyak ke banyak: satu kelas dapat mengimplementasikan beberapa antarmuka, dan setiap antarmuka, pada gilirannya, dapat diimplementasikan oleh banyak kelas.
Antarmuka memiliki penggunaan dua sisi:
- Di satu sisi antarmuka adalah kelas yang mengimplementasikan antarmuka ini.
- Di sisi lain adalah konsumen yang menggunakan antarmuka ini sebagai deskripsi dari jenis data yang mereka bekerja (konsumen).
Misalnya, jika objek selain dari perilaku dasar dapat diserialisasi, maka biarkan ia mengimplementasikan antarmuka Serializable. Dan jika objek dapat dikloning, maka biarkan mengimplementasikan antarmuka lain - "Kloning". Dan jika kita memiliki semacam modul transport yang mentransmisikan objek melalui jaringan, itu akan menerima objek yang mengimplementasikan antarmuka Serializable.
Bayangkan bahwa kerangka transformator dilengkapi dengan tiga slot: slot untuk senjata, untuk generator energi dan untuk beberapa jenis pemindai. Slot ini memiliki antarmuka tertentu: hanya peralatan yang sesuai yang dapat dipasang di setiap slot. Di slot untuk senjata, Anda dapat memasang peluncur roket atau senjata laser, di slot untuk generator listrik - reaktor nuklir atau RTG (generator termoelektrik radioisotop), dan di slot untuk pemindai - radar atau lidar. Intinya adalah bahwa setiap slot memiliki antarmuka koneksi universal, dan perangkat tertentu harus sesuai dengan antarmuka ini. Sebagai contoh, beberapa jenis slot digunakan pada motherboard: slot prosesor memungkinkan Anda untuk menghubungkan berbagai prosesor yang cocok untuk soket ini, dan slot SATA memungkinkan Anda untuk menghubungkan drive SSD atau HDD atau bahkan CD / DVD.
Saya menarik perhatian Anda pada fakta bahwa sistem slot yang dihasilkan untuk transformer adalah contoh penggunaan komposisi. Jika peralatan dalam slot akan diganti selama umur transformator, maka ini sudah merupakan agregasi.
Untuk kejelasan, kami akan memanggil antarmuka, seperti biasa dalam beberapa bahasa, menambahkan huruf kapital "Dan" sebelum nama: IWeapon, IEnergyGenerator, IScanner.
Animasi No. 4Sayangnya, pabrik tidak sesuai dengan gambar, tetapi masih opsional, transformator juga dapat dirakit di halaman.Lapisan abstraksi yang ditunjukkan dalam gambar dalam bentuk antarmuka antara lapisan implementasi dan lapisan konsumen memungkinkan untuk abstrak satu dari yang lain. Anda dapat mengamati ini dengan melihat setiap lapisan secara terpisah: di lapisan implementasi (di sebelah kiri) tidak ada sepatah kata pun tentang kelas Transformer, dan di lapisan konsumen (di sebelah kanan) tidak ada sepatah kata pun tentang implementasi spesifik (tidak ada kata Radar, RocketLauncher, NuclearReactor, dll. d.)Dalam kode ini, kita dapat membuat komponen baru untuk transformer tanpa memengaruhi gambar transformator itu sendiri. Pada saat yang sama dan sebaliknya, kita dapat membuat transformator baru dengan menggabungkan komponen yang ada, atau menambahkan komponen baru tanpa mengubah yang sudah ada.Mengetik bebek
Fenomena yang kita amati dalam arsitektur yang dihasilkan disebut bebek mengetik : jika sesuatu dukun seperti bebek, berenang seperti bebek, dan terlihat seperti bebek, maka kemungkinan besar itu adalah bebek .Menerjemahkan ini ke dalam bahasa transformer, akan terdengar seperti ini: jika sesuatu menembak seperti meriam, dan memuat kembali seperti meriam, kemungkinan besar itu adalah meriam. Jika perangkat menghasilkan energi, kemungkinan besar pembangkit listrik.Berbeda dengan tipifikasi pewarisan secara hierarkis, dengan pengetikan bebek, transformator tidak peduli kelas apa yang diberikan senjata kepadanya, dan apakah itu senjata sama sekali. Yang utama adalah benda ini bisa menembak! Ini bukan keutamaan mengetik bebek, melainkan kompromi. Mungkin ada situasi sebaliknya, seperti pada gambar di bawah ini:
ISP
(Prinsip Segregasi Antarmuka / Prinsip SOLID Keempat) mendorong untuk tidak membuat antarmuka universal yang berani. Sebaliknya, antarmuka harus dibagi menjadi yang lebih kecil dan khusus, ini akan membantu untuk menggabungkan mereka lebih fleksibel dalam mengimplementasikan kelas, tanpa memaksa untuk menerapkan metode yang tidak perlu.Abstraksi
Dalam OOP, semuanya berputar di sekitar abstraksi. Ada fanatik yang mengklaim bahwa abstraksi harus menjadi bagian dari trinitas OOP (enkapsulasi, polimorfisme, pewarisan). Dan inspektur saya untuk pengujian pembebasan bersyarat mengatakan sebaliknya: abstraksi melekat dalam pemrograman apa pun, dan bukan hanya OOP, jadi harus terpisah. Di sisi lain, hal yang sama dapat dikatakan tentang prinsip-prinsip lainnya, tetapi Anda tidak akan menghapus kata-kata dari sebuah lagu. Dengan satu atau lain cara, abstraksi diperlukan, dan terutama dalam OOP.Tingkat abstraksi
Di sini orang tidak dapat gagal mengutip satu lelucon terkenal:- masalah arsitektur apa pun dapat diselesaikan dengan menambahkan lapisan abstraksi tambahan, kecuali untuk masalah sejumlah besar abstraksi.Dalam contoh kami dengan antarmuka, kami menerapkan lapisan abstraksi antara transformer dan komponen, membuat arsitektur lebih fleksibel. Tetapi berapa biayanya? Kami harus memperumit arsitekturnya. Psikoterapis saya mengatakan bahwa kemampuan untuk menyeimbangkan antara kesederhanaan arsitektur dan fleksibilitas aplikasi adalah seni. Memilih jalan tengah, seseorang harus mengandalkan tidak hanya pada pengalaman dan intuisi sendiri, tetapi juga pada konteks proyek saat ini. Karena orang tersebut belum belajar untuk melihat masa depan, maka perlu secara analitik memperkirakan tingkat abstraksi apa dan dengan tingkat probabilitas apa yang dapat berguna dalam proyek ini, berapa banyak waktu yang diperlukan untuk mengembangkan arsitektur yang fleksibel, dan apakah waktu yang dihabiskan akan terbayar di masa depan.Pilihan tingkat abstraksi yang salah mengarah ke salah satu dari dua masalah:- , , , ( )
- , , , , . ( )
Penting juga dipahami bahwa tingkat abstraksi ditentukan bukan untuk keseluruhan proyek secara keseluruhan, tetapi secara terpisah untuk komponen yang berbeda. Di beberapa tempat, sistem abstraksi mungkin tidak cukup, tetapi di suatu tempat sebaliknya - gagal. Namun, pilihan tingkat abstraksi yang salah dapat dikoreksi dengan refactoring yang tepat waktu. Kata kunci tepat waktu . Penundaan refactoring bermasalah ketika banyak mekanisme sudah dilaksanakan pada tingkat abstraksi ini. Melakukan ritual refactoring dalam menjalankan sistem dapat melibatkan rasa sakit akut di tempat-tempat yang sulit dijangkau seorang programmer. Ini tentang bagaimana mengubah fondasi di rumah - lebih murah untuk membangun rumah di sebelah dari awal.Mari kita lihat definisi tingkat abstraksi dari opsi yang memungkinkan pada contoh permainan hipotetis "transformers-online." Dalam hal ini, level abstraksi akan bertindak sebagai lapisan, setiap lapisan berikutnya yang dipertimbangkan akan berada di atas yang sebelumnya, mengambil bagian dari fungsional dari padanya.Lapisan pertama. Permainan memiliki satu kelas transformator, semua properti dan perilaku dijelaskan di dalamnya. Ini adalah tingkat abstraksi yang sepenuhnya kayu, cocok untuk permainan kasual, yang tidak menyiratkan fleksibilitas khusus.Tingkat kedua.Gim ini memiliki trafo dasar dengan kemampuan dasar dan kelas trafo dengan spesialisasi mereka sendiri (seperti scout, pesawat serang, dukungan), yang dijelaskan dengan metode tambahan. Dengan demikian, pemain diberi kesempatan untuk memilih, dan pengembangan kelas baru disederhanakan untuk pengembang.Tingkat ketiga Selain klasifikasi transformator, agregasi diperkenalkan menggunakan sistem slot dan komponen (seperti dalam contoh kami dengan reaktor, senjata dan radar). Sekarang bagian dari perilaku akan ditentukan oleh staf yang dipasang oleh pemain di transformernya. Ini memberi pemain lebih banyak pilihan untuk menyesuaikan mekanika permainan karakter, dan memberi pengembang kesempatan untuk menambahkan modul ekspansi yang sama ini, yang pada gilirannya menyederhanakan pekerjaan desainer game untuk merilis konten baru.Tingkat keempat. Anda juga dapat memasukkan agregasi Anda sendiri dalam komponen, yang memungkinkan Anda memilih bahan dan bagian dari mana komponen ini dirakit. Pendekatan ini akan memberikan pemain kesempatan tidak hanya untuk mengisi transformator dengan komponen yang diperlukan, tetapi juga untuk secara mandiri menghasilkan komponen-komponen ini dari berbagai bagian. Terus terang, saya belum pernah bertemu tingkat abstraksi sedemikian dalam permainan, dan bukan tanpa alasan! Lagi pula, ini disertai dengan komplikasi arsitektur yang signifikan, dan penyesuaian keseimbangan dalam permainan seperti itu berubah menjadi neraka. Tapi saya tidak mengesampingkan bahwa permainan seperti itu ada.
Seperti yang Anda lihat, setiap lapisan yang dijelaskan, pada prinsipnya, memiliki hak untuk hidup. Itu semua tergantung pada kelenturan seperti apa yang kita inginkan dalam proyek. Jika kerangka acuan tidak mengatakan apa-apa tentang hal ini, atau penulis proyek sendiri tidak tahu apa yang dibutuhkan oleh bisnis, Anda dapat melihat proyek serupa di area ini dan fokus pada mereka.Pola desain
Dekade pembangunan telah mengarah pada pembentukan daftar solusi arsitektur yang paling umum digunakan, yang dari waktu ke waktu telah diklasifikasikan oleh masyarakat, dan disebut pola desain . Itulah sebabnya ketika saya pertama kali membaca tentang pola, saya terkejut menemukan bahwa ternyata saya sudah menggunakan banyak dari mereka dalam praktik, saya hanya tidak tahu bahwa solusi ini memiliki nama.Pola desain, seperti abstraksi, adalah karakteristik tidak hanya dari pengembangan OOP, tetapi juga dari paradigma lain. Secara umum, topik pola berada di luar cakupan artikel ini, tetapi saya ingin memperingatkan pengembang muda yang hanya ingin berkenalan dengan pola. Ini jebakan! Sekarang saya akan menjelaskan alasannya.Tujuan dari pola adalah untuk membantu menyelesaikan masalah arsitektur yang sudah ditemukan, atau kemungkinan besar akan ditemukan selama pengembangan proyek. Jadi, setelah membaca tentang pola, seorang pemula mungkin memiliki godaan yang tak tertahankan untuk menggunakan pola bukan untuk memecahkan masalah, tetapi untuk menghasilkan mereka. Dan karena pengembang tidak terkendali dalam keinginannya, ia mungkin tidak mulai menyelesaikan masalah dengan bantuan pola, tetapi dapat menyesuaikan tugas apa pun dengan solusi dengan bantuan pola.Nilai lain dari pola adalah formalisasi terminologi. Jauh lebih mudah bagi seorang kolega untuk mengatakan bahwa "rantai tugas" digunakan di tempat ini daripada menggambar perilaku dan hubungan objek pada selembar kertas selama setengah jam.Kesimpulan
Dalam kondisi modern, keberadaan kelas kata dalam kode Anda tidak menjadikan Anda seorang programmer OOP. Karena jika Anda tidak menggunakan mekanisme yang dijelaskan dalam artikel (polimorfisme, komposisi, pewarisan, dll.), Dan alih-alih menggunakan kelas hanya untuk mengelompokkan fungsi dan data, maka ini bukan OOP. Hal yang sama dapat dipecahkan oleh beberapa ruang nama dan struktur data. Jangan bingung, kalau tidak Anda akan malu saat wawancara.Saya ingin menyelesaikan lagu saya dengan kata-kata penting. Setiap mekanisme, prinsip, dan pola yang diuraikan, serta OOP secara keseluruhan, tidak boleh diterapkan di tempat yang tidak ada gunanya atau bisa berbahaya. Ini mengarah ke artikel dengan tajuk berita aneh seperti "Warisan adalah penyebab penuaan dini" atau "Singleton dapat menyebabkan kanker."Saya serius.
Jika kita mempertimbangkan kasus singleton, maka penggunaannya yang luas tanpa sepengetahuan kasus tersebut, telah menyebabkan masalah arsitektur yang serius di banyak proyek. Dan para pecinta palu palu dengan mikroskop berbaik hati memanggilnya antipattern. Berhati-hatilah.Sayangnya, dalam mendesain tidak ada resep yang jelas untuk semua kesempatan, di mana yang sesuai dan di mana yang tidak pantas. Ini secara bertahap akan cocok dengan kepala Anda dengan pengalaman.