Menghindari Jebakan Berorientasi Objek, Bermigrasi dari C, Apa yang Berhasil untuk Anda?

12

Saya telah pemrograman dalam bahasa prosedural untuk beberapa waktu sekarang, dan reaksi pertama saya terhadap masalah adalah mulai memecahnya menjadi tugas untuk dilakukan daripada mempertimbangkan entitas yang berbeda (objek) yang ada dan hubungan mereka.

Saya telah mengikuti kursus universitas di OOP, dan memahami dasar-dasar enkapsulasi, abstraksi data, polimorfisme, modularitas, dan pewarisan.

Saya membaca /programming/2688910/learning-to-think-in-the-object-oriented-way dan /programming/1157847/learning-object-oriented-thinking , dan akan melihat beberapa buku yang ditunjukkan dalam jawaban itu.

Saya pikir beberapa proyek saya yang berukuran sedang hingga besar akan mendapat manfaat dari penggunaan OOP yang efektif, tetapi sebagai pemula saya ingin menghindari kesalahan umum yang memakan waktu.

Berdasarkan pengalaman Anda, apa saja jebakan ini dan apa cara yang masuk akal di sekitar mereka? Jika Anda bisa menjelaskan mengapa itu adalah jebakan, dan bagaimana saran Anda efektif dalam mengatasi masalah itu akan dihargai.

Saya berpikir seperti "Apakah biasa memiliki cukup banyak metode pengamat dan pengubah dan menggunakan variabel pribadi atau apakah ada teknik untuk mengkonsolidasikan / menguranginya?"

Saya tidak khawatir tentang menggunakan C ++ sebagai bahasa OO murni, jika ada alasan yang baik untuk mencampur metode. (Mengingatkan alasan untuk menggunakan GOTO, meskipun hemat.)

Terima kasih!

Stephen
sumber
2
tidak layak untuk jawaban yang lengkap, tetapi yang penting yang membuat saya butuh waktu lama untuk menerima (yaitu saya membaca tentang hal itu banyak waktu tetapi memperlakukannya sebagai pembicaraan fanboy): lebih suka funtcions gratis daripada fungsi anggota. Ini membuat kelas Anda minimal yang merupakan Good Thing.
stijn
@stijn Pada dasarnya Anda mengatakan jika tidak perlu di kelas, jangan taruh di sana. Sebagai contoh saya melihat banyak fungsi anggota utilitas yang dapat dengan mudah menjadi fungsi bebas dalam kode yang saya baca sejauh ini.
Stephen
ya itu dia. Jika Anda mencari 'lebih suka bukan-bukan-teman' Anda akan menemukan banyak informasi tentang itu. Pada akhirnya, ia berpegang pada mematuhi Prinsip Responsabilitas Tunggal
stijn

Jawaban:

10

Satu hal besar yang saya pelajari adalah merancang kelas dari luar. Rancang antarmuka sebelum Anda mulai berpikir tentang implementasinya. Ini akan membuat kelas jauh, lebih intuitif untuk pengguna Anda (mereka yang menggunakan kelas) daripada menulis algoritma yang mendasari dan membangun kelas, dan menulis fungsi anggota publik baru sesuai kebutuhan.

Dominic Gurto
sumber
7
Menambah ini, kita dapat 'memprogram dengan niat,' yaitu, menulis beberapa kode sampel yang akan menggunakan kelas baru, melihat jenis metode dan kebijakan apa yang membuatnya nyaman untuk digunakan. Kemudian gunakan informasi itu sebagai dasar untuk implementasi.
2
Besar dalam teori - desain antarmuka dan Anda pada dasarnya selesai. Tetapi dalam praktiknya tidak sesederhana itu. Desain dan implementasi antarmuka sering berjalan beriringan dalam iterasi berurutan sampai antarmuka final terkristalisasi. Pada saat itu Anda cenderung memiliki implementasi akhir juga.
Gene Bushuyev
9

Ya, yang pertama adalah perangkap mengungkapkan terlalu banyak informasi. Defaultnya seharusnya private, bukan public.

Setelah itu muncul terlalu banyak getter / setter. Katakanlah saya memiliki anggota data. Apakah saya benar - benar membutuhkan data ini di kelas lain? Ok, buat pengambil. Apakah saya benar-benar perlu mengubah data ini selama umur objek? Lalu buat setter.

Kebanyakan programmer pemula memiliki default untuk membuat pengambil / penyetel untuk setiap anggota data. Ini berantakan antarmuka dan sering merupakan pilihan desain yang buruk.

orlp
sumber
2
ya, ini cukup populer di kalangan mereka yang memahami enkapsulasi secara dangkal untuk membuat data pribadi dan kemudian meniup enkapsulasi dengan getter dan setter.
Gene Bushuyev
Java adalah satu-satunya bahasa populer yang masih membutuhkan metode get / set. Setiap bahasa lain mendukung properti, jadi tidak ada perbedaan sintaksis antara anggota data publik dan properti. Bahkan di Jawa, tidak ada salahnya memiliki anggota data publik jika Anda juga mengontrol semua pengguna kelas.
kevin cline
Anggota data publik lebih sulit untuk dipelihara. Dengan getter / setters (atau properti), Anda dapat menjaga antarmuka saat mengubah representasi data internal, tanpa mengubah kode luar. Dalam bahasa yang sifatnya identik secara sintaksis dengan variabel anggota dari sudut pandang konsumen, titik ini tidak berlaku.
tdammers
Sejauh ini saya pikir saya melihat anggota pribadi "semacam" sebagai variabel lokal dalam suatu fungsi ... seluruh dunia tidak perlu tahu apa-apa tentang mereka agar fn dapat beroperasi ... dan jika fn perubahan, hanya antarmuka yang harus konsisten. Saya tidak cenderung pergi dengan pengambil spam / penyetel jadi saya mungkin berada di jalur yang benar, bahkan melihat kelas penyangga yang saya tulis, tidak ada anggota data publik sama sekali. Terima kasih!
Stephen
2

Ketika saya melewati jurang itu, saya memutuskan pendekatan berikut:

0) Saya mulai lambat, dengan aplikasi prosedural ukuran kecil / menengah, dan tidak ada hal penting di tempat kerja.

1) pemetaan 1st-pass sederhana tentang bagaimana saya akan menulis program dari awal dengan gaya OO - yang paling penting bagi saya pada waktu itu, dan ini subyektif IS - adalah untuk mengetahui semua kelas dasar. Objek saya adalah merangkum sebanyak mungkin di kelas dasar. Metode virtual murni untuk segala yang mungkin terjadi di kelas dasar.

2) Kemudian langkah selanjutnya adalah membuat derivasi.

3) langkah terakhir adalah - dalam kode prosedur asli, pisahkan struktur data dari kode pengamat / pengubah. Kemudian gunakan menyembunyikan data dan memetakan semua data umum ke dalam kelas dasar, dan dalam subkelas pergi data yang tidak umum di seluruh program. Dan perlakuan yang sama untuk pengamat prosedural / kode pengubah - semua logika 'digunakan di mana saja' masuk ke kelas dasar. Dan melihat / memodifikasi logika yang hanya bertindak pada sebagian data masuk ke kelas turunan.

Ini subjektif tetapi FAST, jika Anda tahu kode prosedural dan struktur data dengan baik. GAGAL dalam tinjauan kode adalah ketika sedikit data atau logika tidak muncul di kelas dasar tetapi digunakan di mana-mana.


sumber
2

Lihatlah proyek sukses lainnya yang menggunakan OOP untuk mendapatkan kesan gaya yang baik. Saya merekomendasikan untuk melihat Qt , sebuah proyek yang selalu saya perhatikan ketika membuat keputusan desain sendiri.

rcv
sumber
Iya! Sebelum seseorang menjadi penguasa sesuatu, ia belajar untuk meniru tuan-tuan besar yang bekerja di depannya. Mempelajari kode yang baik yang diterapkan orang lain adalah cara yang baik untuk belajar. Saya akan merekomendasikan melihat dorongan, mulai dari desain sederhana dan pergi lebih dalam saat pemahaman seseorang meningkat.
Gene Bushuyev
1

Bergantung pada siapa Anda berbicara, semua data dalam OOP harus pribadi atau dilindungi, dan hanya tersedia melalui pengakses dan mutator. Secara umum, saya pikir ini adalah praktik yang baik, tetapi ada beberapa kesempatan di mana saya menyimpang dari norma ini. Sebagai contoh, jika Anda memiliki kelas (di Jawa, katakanlah) yang tujuannya hanya untuk memasukkan beberapa bagian data ke dalam unit logis, masuk akal untuk membiarkan bidang publik. Jika itu adalah kapsul yang tidak dapat diubah, tandai saja mereka sudah final dan inisialisasi mereka di konstruktor. Ini mengurangi kelas (dalam hal ini) menjadi sedikit lebih dari sebuah struct (pada kenyataannya, menggunakan C ++, Anda harus benar-benar menyebutnya sebagai struct. Bekerja seperti sebuah kelas, tetapi visibilitas default adalah publik, dan maksud Anda lebih jelas), tetapi Saya pikir Anda akan menemukan bahwa menggunakannya jauh lebih nyaman dalam kasus ini.

Satu hal yang pasti tidak ingin Anda lakukan adalah memiliki bidang yang harus diperiksa untuk konsistensi dalam mutator, dan biarkan publik.

jpm
sumber
3
Saya juga menyarankan, jika Anda memiliki kelas seperti itu yang hanya menyimpan data publik, Anda harus mendeklarasikannya sebagai structs - itu tidak membuat perbedaan semantik, tetapi itu menjelaskan maksudnya, dan membuat penggunaannya tampak lebih alami, terutama untuk programmer C.
1
Ya, saya setuju di sini jika Anda menggunakan C ++ (yang pertanyaannya sebutkan), tetapi saya melakukan sebagian besar pekerjaan saya di Jawa, dan sayangnya, kami tidak memiliki struct.
Anda perlu membedakan dengan jelas antara kelas agregat (kasus jarang) dan kelas dengan fungsi (kasus umum). Yang terakhir harus mempraktikkan enkapsulasi dan mengakses anggotanya melalui antarmuka publik saja, tidak boleh ada data yang dibuka untuk umum.
Gene Bushuyev
1

Buku Implementasi Kent Beck adalah landasan yang sangat baik dalam cara menggunakan, bukan menyalahgunakan, mekanisme berorientasi objek.

Steven A. Lowe
sumber
1

Saya tidak khawatir tentang menggunakan C ++ sebagai bahasa OO murni, jika ada alasan yang baik untuk mencampur metode. (Mengingatkan alasan untuk menggunakan GOTO, meskipun hemat.)

Saya tidak benar-benar berpikir saya punya banyak untuk menawarkan percakapan sampai saya melihat ini sedikit. Saya harus tidak setuju dengan sentimen. OOP hanyalah salah satu dari paradigma yang dapat dan harus digunakan dalam C ++. Terus terang, menurut saya itu bukan salah satu fitur terkuatnya.

Dari sudut pandang OO saya pikir C ++ sebenarnya jatuh agak pendek. Gagasan memiliki fungsi non-virtual misalnya adalah tanda centang dalam hal ini. Saya memiliki argumen dengan mereka yang tidak setuju dengan saya, tetapi anggota non-virtual tidak cocok dengan paradigma sejauh yang saya ketahui. Polimorfisme adalah komponen kunci untuk OO dan kelas-kelas dengan fungsi non-virtual bukanlah polimorfik dalam arti OO. Jadi sebagai bahasa OO saya pikir C ++ sebenarnya agak lemah jika dibandingkan dengan bahasa seperti Java atau Objective-C.

Pemrograman generik di sisi lain, C ++ memiliki yang satu ini cukup bagus. Saya pernah mendengar bahwa ada bahasa yang lebih baik untuk ini, tetapi kombinasi objek dan fungsi generik adalah sesuatu yang cukup kuat dan ekspresif. Selain itu dapat sangat cepat baik dalam waktu pemrograman dan waktu pemrosesan. Ini benar-benar di daerah ini yang saya pikir C ++ bersinar meskipun diakui itu bisa lebih baik (dukungan bahasa untuk konsep misalnya). Seseorang yang berpikir bahwa mereka harus berpegang teguh pada paradigma OO dan memperlakukan yang lain pada urutan pernyataan kebohongan dalam tingkat amoralitas benar-benar hilang dengan tidak melihat paradigma ini.

Kapasitas metaprogramming template juga cukup mengesankan. Lihat perpustakaan Boost.Units misalnya. Perpustakaan ini menyediakan dukungan tipe untuk jumlah dimensi. Saya telah memanfaatkan perpustakaan ini secara ekstensif di perusahaan teknik tempat saya bekerja saat ini. Ini hanya memberikan umpan balik yang jauh lebih cepat untuk satu aspek dari programmer yang mungkin, atau bahkan kesalahan spesifikasi. Tidak mungkin mengkompilasi program yang menggunakan rumus di mana kedua sisi operator '=' tidak setara secara dimensi tanpa casting eksplisit. Saya pribadi tidak punya pengalaman dengan bahasa lain di mana ini mungkin, dan tentu saja tidak dengan bahasa yang juga memiliki kekuatan dan kecepatan C ++.

Metaprogramming adalah paradigma yang murni fungsional.

Jadi sungguh, saya pikir Anda sudah melangkah ke C ++ dengan beberapa kesalahpahaman yang disayangkan. Paradigma lain selain OO tidak harus dihindari, mereka harus LEVERAGED. Gunakan paradigma yang wajar untuk aspek masalah yang sedang Anda kerjakan. Jangan memaksakan objek pada apa yang pada dasarnya bukan masalah rawan objek. Sejauh yang saya ketahui, OO bahkan tidak setengah cerita untuk C ++.

Edward Strange
sumber
Bukankah kata kunci virtual menyediakan fungsionalitas kelas virtual dalam C ++? Sejauh komentar goto, apa yang saya kendarai adalah bahwa saya tidak khawatir melanggar aturan empiris, selama saya mengerti alasannya. Namun, saya telah melihat lebih jauh ke arah menghindari imperatif / prosedural yang mendukung OO daripada yang mungkin diperlukan. Terima kasih.
Stephen
metode virtual bukanlah prasyarat untuk polimorfisme, itu hanya cara umum untuk melakukannya. sebenarnya, semua yang lain sama, kemudian membuat metode virtual sebenarnya melemahkan enkapsulasi, karena Anda meningkatkan ukuran api kelas, dan Anda membuatnya lebih sulit untuk memastikan Anda mengikuti liskov dan sebagainya. membuat sesuatu yang virtual hanya jika Anda membutuhkan sebuah jahitan, suatu tempat untuk menyuntikkan perilaku baru melalui warisan (meskipun warisan juga sesuatu yang harus diwaspadai di OOP). virtual demi virtual tidak membuat kelas "lebih banyak OOP"
sara
1

Saya ingin menerima jawaban untuk pertanyaan ini, tetapi saya tidak dapat memutuskan satu jawaban untuk melimpahkan tanda centang. Karena itu saya telah mengangkat penulis asli dan membuat ini sebagai jawaban ringkasan. Terima kasih kepada semua orang yang meluangkan waktu beberapa menit, saya menemukan bahwa wawasan yang Anda berikan memberi saya arahan yang baik dan sedikit kepastian bahwa saya tidak keluar dari jalur.

@ nightcracker

Ya, yang pertama adalah perangkap mengungkapkan terlalu banyak informasi. Defaultnya harus pribadi, bukan publik. Setelah itu muncul terlalu banyak getter / setter.

Saya merasa bahwa saya telah mengamati masalah ini di masa lalu. Komentar Anda membuat saya juga ingat bahwa dengan menyembunyikan variabel yang mendasarinya dan implementasinya, saya bebas untuk mengubah implementasinya tanpa merusak apa pun yang bergantung padanya.

Dominic Gurto

Rancang antarmuka bahkan sebelum Anda mulai memikirkan implementasinya. Desain dan implementasi Antarmuka Gene Bushuyev sering berjalan beriringan dalam iterasi berurutan sampai antarmuka final dikristalisasi.

Saya pikir komentar Dominic adalah cita-cita yang bagus untuk dicita-citakan, tetapi saya pikir komentar Gene benar-benar menyentuh kenyataan situasi. Sejauh ini saya sudah melihat ini dalam aksi ... dan merasa sedikit lebih baik bahwa itu tidak biasa. Saya pikir bahwa ketika saya dewasa sebagai programmer saya akan condong ke arah desain yang lebih lengkap, tetapi sekarang saya masih menderita melompat dan mendapatkan beberapa kode yang ditulis-itis.

wantTheBest

Saya mulai lambat, dengan aplikasi prosedural ukuran kecil / menengah, dan tidak ada hal-hal penting di tempat kerja. dalam kode prosedural asli, pisahkan struktur data dari kode pengamat / pengubah

Ini sangat masuk akal ... Saya menyukai gagasan menjaga hal-hal bekerja di tempat kerja, tetapi untuk memperbaiki beberapa hal yang tidak kritis dengan kelas.

jpm

Satu hal yang pasti tidak ingin Anda lakukan adalah memiliki bidang yang harus diperiksa untuk konsistensi dalam mutator, dan biarkan publik

Saya sudah tahu sebentar bahwa ini adalah salah satu kekuatan merangkum data ... mampu menegakkan konsistensi dan dalam hal ini kondisi / rentang / dll.

Eddie yang gila

Seseorang yang berpikir bahwa mereka harus berpegang teguh pada paradigma OO dan memperlakukan yang lain pada urutan pernyataan kebohongan dalam tingkat amoralitas benar-benar hilang dengan tidak melihat paradigma ini. Kapasitas metaprogramming template juga cukup mengesankan.

Saya awalnya sangat merindukan jawaban Crazy Eddie, saya pikir karena saya belum membaca beberapa topik yang disebutkan ... seperti metaprogramming. Saya pikir pesan besar dalam posting CE adalah bahwa C ++ adalah perpaduan antara kemampuan dan gaya yang masing-masing harus digunakan untuk potensi terbaik mereka ... termasuk keharusan jika itu yang masuk akal.

Jadi sekali lagi, terima kasih kepada semua orang yang merespons!

Stephen
sumber
0

Jebakan terbesar adalah keyakinan bahwa OOP adalah peluru perak, atau "satu paradigma sempurna."

alternatif
sumber