Saya mengalami sesuatu yang sulit dengan merancang kelas dengan cara oo. Saya pernah membaca bahwa objek memperlihatkan perilaku mereka, bukan data mereka; Oleh karena itu, daripada menggunakan pengambil / setter untuk memodifikasi data, metode kelas yang diberikan harus "kata kerja" atau tindakan yang beroperasi pada objek. Misalnya, dalam objek 'Akun', kita akan memiliki metode Withdraw()
dan Deposit()
bukannya setAmount()
dll. Lihat: Mengapa metode pengambil dan penyetel adalah jahat .
Jadi misalnya, diberikan kelas Pelanggan yang menyimpan banyak informasi tentang pelanggan, misalnya Nama, DOB, Telp, Alamat dll., Bagaimana seseorang menghindari pengambil / penentu untuk mendapatkan dan mengatur semua atribut itu? Metode tipe 'Perilaku' apa yang dapat ditulis untuk mengisi semua data itu?
sumber
name()
padaCustomer
adalah sebagai jelas, atau lebih jelas, dari metode yang disebutgetName()
.Jawaban:
Sebagaimana dinyatakan dalam beberapa jawaban dan komentar, DTOs yang tepat dan berguna dalam beberapa situasi, terutama dalam mentransfer data melintasi batas-batas (misalnya serialisasi ke JSON untuk mengirim melalui layanan web). Untuk sisa jawaban ini, saya akan sedikit banyak mengabaikan itu dan berbicara tentang kelas domain, dan bagaimana mereka dapat dirancang untuk meminimalkan (jika tidak menghilangkan) getter dan setter, dan masih berguna dalam proyek besar. Saya juga tidak akan berbicara tentang mengapa menghapus getter atau setter, atau kapan melakukannya, karena itu adalah pertanyaan mereka sendiri.
Sebagai contoh, bayangkan bahwa proyek Anda adalah permainan papan seperti Catur atau Battleship. Anda mungkin memiliki berbagai cara untuk mewakili ini dalam lapisan presentasi (aplikasi konsol, layanan web, GUI, dll.), Tetapi Anda juga memiliki domain inti. Satu kelas yang mungkin Anda miliki adalah
Coordinate
, mewakili posisi di papan tulis. Cara "jahat" untuk menulisnya adalah:(Saya akan menulis contoh kode dalam C # daripada Java, untuk singkatnya dan karena saya lebih akrab dengannya. Mudah-mudahan itu bukan masalah. Konsepnya sama dan terjemahannya harus sederhana.)
Menghapus Setters: Immutability
Sementara getter dan setter publik keduanya berpotensi bermasalah, setter adalah yang jauh lebih "jahat" dari keduanya. Mereka juga biasanya lebih mudah dihilangkan. Prosesnya sederhana, atur nilai dari dalam konstruktor. Metode apa pun yang sebelumnya bermutasi objek seharusnya mengembalikan hasil baru. Begitu:
Perhatikan bahwa ini tidak melindungi terhadap metode lain di kelas yang bermutasi X dan Y. Agar lebih tidak dapat diubah, Anda bisa menggunakan
readonly
(final
di Jawa). Tetapi bagaimanapun juga - apakah Anda membuat properti Anda benar-benar tidak dapat diubah atau hanya mencegah mutasi publik langsung melalui setter - itu memang menghilangkan trik setter publik Anda. Dalam sebagian besar situasi, ini berfungsi dengan baik.Menghapus Getters, Bagian 1: Merancang untuk Perilaku
Di atas semua baik dan bagus untuk setter, tetapi dalam hal getter, kami benar-benar menembak diri sendiri sebelum memulai. Proses kami adalah memikirkan apa yang dimaksud dengan koordinat - data yang diwakilinya - dan membuat kelas di sekitarnya. Sebagai gantinya, kita harus mulai dengan perilaku apa yang kita butuhkan dari seorang koordinator. Omong-omong, proses ini dibantu oleh TDD, di mana kita hanya mengekstrak kelas-kelas seperti ini begitu kita membutuhkannya, jadi kita mulai dengan perilaku yang diinginkan dan bekerja dari sana.
Jadi katakanlah tempat pertama yang Anda perlukan
Coordinate
adalah untuk deteksi tabrakan: Anda ingin memeriksa apakah dua potong menempati ruang yang sama di papan tulis. Inilah cara "jahat" (konstruktor dihilangkan karena singkatnya):Dan inilah cara yang baik:
(
IEquatable
implementasi disingkat karena kesederhanaan). Dengan mendesain untuk perilaku daripada memodelkan data, kami telah berhasil menghapus getter kami.Perhatikan ini juga relevan dengan contoh Anda. Anda mungkin menggunakan ORM, atau menampilkan informasi pelanggan di situs web atau sesuatu, dalam hal ini semacam
Customer
DTO mungkin masuk akal. Tetapi hanya karena sistem Anda mencakup pelanggan dan mereka terwakili dalam model data tidak secara otomatis berarti Anda harus memilikiCustomer
kelas di domain Anda. Mungkin saat Anda mendesain untuk perilaku, seseorang akan muncul, tetapi jika Anda ingin menghindari getter, jangan membuatnya terlebih dahulu.Menghapus Getters, Bagian 2: Perilaku Eksternal
Jadi di atas adalah awal yang baik, tetapi cepat atau lambat Anda mungkin akan mengalami situasi di mana Anda memiliki perilaku yang berhubungan dengan kelas, yang dalam beberapa cara tergantung pada negara kelas, tetapi yang bukan milik atas kelas. Perilaku semacam ini adalah yang biasanya hidup di lapisan layanan aplikasi Anda.
Mengambil
Coordinate
contoh kami , pada akhirnya Anda akan ingin mewakili permainan Anda kepada pengguna, dan itu mungkin berarti menggambar ke layar. Anda mungkin, misalnya, memiliki proyek UI yang digunakanVector2
untuk mewakili suatu titik di layar. Tetapi tidak pantas bagiCoordinate
kelas untuk mengambil alih konversi dari koordinat ke titik di layar - yang akan membawa segala macam masalah presentasi ke dalam domain inti Anda. Sayangnya situasi semacam ini melekat dalam desain OO.Pilihan pertama , yang sangat umum dipilih, adalah hanya mengekspos para pengambil sialan dan mengatakan persetan dengan itu. Ini memiliki keunggulan kesederhanaan. Tetapi karena kita berbicara tentang menghindari getter, katakanlah demi argumen, kita menolak yang ini dan melihat opsi apa yang ada.
Opsi kedua adalah menambahkan semacam
.ToDTO()
metode di kelas Anda. Ini - atau yang serupa - mungkin diperlukan juga, misalnya ketika Anda ingin menyimpan permainan, Anda perlu menangkap hampir semua negara Anda. Tetapi perbedaan antara melakukan ini untuk layanan Anda dan hanya mengakses pengambil secara langsung lebih atau kurang estetika. Itu masih memiliki "kejahatan" sebanyak itu.Opsi ketiga - yang saya lihat didukung oleh Zoran Horvat dalam beberapa video Pluralsight- adalah menggunakan versi modifikasi dari pola pengunjung. Ini adalah penggunaan yang cukup tidak biasa dan variasi dari pola dan saya pikir jarak tempuh orang akan sangat bervariasi pada apakah itu menambah kompleksitas tanpa keuntungan nyata atau apakah itu kompromi yang bagus untuk situasi tersebut. Idenya pada dasarnya adalah untuk menggunakan pola pengunjung standar, tetapi minta
Visit
metode mengambil status yang mereka butuhkan sebagai parameter, bukan kelas yang mereka kunjungi. Contohnya dapat ditemukan di sini .Untuk masalah kami, solusi menggunakan pola ini adalah:
Seperti yang Anda mungkin tahu,
_x
dan_y
tidak benar - benar dienkapsulasi lagi. Kita dapat mengekstraknya dengan membuatIPositionTransformer<Tuple<int,int>>
yang baru mengembalikannya secara langsung. Tergantung pada rasanya, Anda mungkin merasa ini membuat seluruh latihan menjadi sia-sia.Namun, dengan getter publik, sangat mudah untuk melakukan hal-hal dengan cara yang salah, hanya menarik data secara langsung dan menggunakannya melanggar Tell, Don't Ask . Sedangkan menggunakan pola ini sebenarnya lebih mudah untuk melakukannya dengan cara yang benar: ketika Anda ingin membuat perilaku, Anda akan secara otomatis mulai dengan membuat tipe yang terkait dengannya. Pelanggaran terhadap TDA akan sangat berbau dan mungkin membutuhkan solusi yang lebih sederhana dan lebih baik. Dalam praktiknya, poin-poin ini membuatnya jauh lebih mudah untuk melakukannya dengan cara yang benar, OO, daripada cara "jahat" yang didorong oleh para pengecut.
Akhirnya , bahkan jika itu awalnya tidak jelas, mungkin sebenarnya ada cara untuk mengekspos cukup dari apa yang Anda butuhkan sebagai perilaku untuk menghindari keharusan untuk mengekspos keadaan. Misalnya, menggunakan versi kami sebelumnya
Coordinate
yang hanya anggota publikEquals()
(dalam praktiknya akan membutuhkanIEquatable
implementasi penuh ), Anda dapat menulis kelas berikut di lapisan presentasi Anda:Ternyata, mungkin secara mengejutkan, bahwa semua perilaku yang benar - benar kita butuhkan dari koordinat untuk mencapai tujuan kita adalah pengecekan kesetaraan! Tentu saja, solusi ini dirancang untuk masalah ini, dan membuat asumsi tentang penggunaan / kinerja memori yang dapat diterima. Itu hanya contoh yang sesuai dengan domain masalah khusus ini, bukan cetak biru untuk solusi umum.
Dan lagi, pendapat akan bervariasi tergantung pada apakah dalam praktiknya ini adalah kompleksitas yang tidak perlu. Dalam beberapa kasus, tidak ada solusi seperti ini yang mungkin ada, atau mungkin sangat aneh atau kompleks, dalam hal ini Anda dapat kembali ke tiga di atas.
sumber
Customer
dimiliki suatu kelas yang mengharuskan untuk dapat mengubah nomor teleponnya? Mungkin nomor telepon pelanggan berubah dan saya perlu bertahan bahwa perubahan dalam database, tetapi tidak ada yang menjadi tanggung jawab objek domain yang menyediakan perilaku. Itu adalah masalah akses-data, dan mungkin akan ditangani dengan DTO dan, katakanlah, repositori.Customer
data objek domain relatif segar (selaras dengan db) adalah masalah mengelola daur hidupnya, yang juga bukan tanggung jawabnya sendiri, dan mungkin sekali lagi akan berakhir di repositori atau pabrik atau wadah IOC atau instantiate apapunCustomer
s.Cara paling sederhana untuk menghindari setter adalah menyerahkan nilai ke metode konstruktor saat Anda
new
menaikkan objek. Ini juga pola yang biasa ketika Anda ingin membuat objek tidak berubah. Yang mengatakan, hal-hal tidak selalu jelas di dunia nyata.Memang benar bahwa metode harus tentang perilaku. Namun, beberapa objek, seperti Pelanggan, ada terutama untuk menyimpan informasi. Itu adalah jenis objek yang paling diuntungkan dari getter dan setter; jika tidak perlu sama sekali untuk metode seperti itu, kami hanya akan menghilangkannya sama sekali.
Bacaan Lebih Lanjut
Kapan Getters dan Setters Dibenarkan
sumber
setEvil(null);
Sangat baik untuk memiliki objek yang mengekspos data daripada perilaku. Kami hanya menyebutnya "objek data". Pola ada di bawah nama-nama seperti Objek Transfer Data atau Nilai Objek. Jika tujuan objek adalah untuk menyimpan data, maka getter dan setter berlaku untuk mengakses data.
Jadi mengapa seseorang mengatakan "metode pengambil dan penyetel itu jahat"? Anda akan sering melihat ini - seseorang mengambil panduan yang benar-benar valid dalam konteks tertentu dan kemudian menghapus konteksnya untuk mendapatkan informasi utama yang lebih keras. Misalnya, " mengunggulkan komposisi daripada warisan " adalah prinsip yang bagus, tetapi tak lama kemudian seseorang akan menghapus konteks dan menulis " Mengapa meluas itu jahat " (hai, penulis yang sama, kebetulan sekali!) Atau " warisan itu jahat dan harus hancur ".
Jika Anda melihat konten artikel yang sebenarnya memiliki beberapa poin valid, itu hanya memperpanjang poin untuk membuat headline klik-baity. Sebagai contoh, artikel tersebut menyatakan bahwa detail implementasi tidak boleh diekspos. Ini adalah prinsip enkapsulasi dan penyembunyian data yang mendasar dalam OO. Namun, metode pengambil tidak secara definisi mengekspos detail implementasi. Dalam kasus objek data Pelanggan , properti Nama , Alamat dll. Bukan detail implementasi melainkan seluruh tujuan objek dan harus menjadi bagian dari antarmuka publik.
Baca kelanjutan dari artikel yang Anda tautkan, untuk melihat bagaimana ia menyarankan sebenarnya pengaturan properti seperti 'nama' dan 'gaji' pada objek 'Karyawan'-tanpa menggunakan setter jahat. Ternyata ia menggunakan pola dengan 'Eksportir' yang diisi dengan metode yang disebut add Name, tambahkan Gaji yang pada gilirannya menetapkan bidang dengan nama yang sama ... Jadi pada akhirnya ia akhirnya menggunakan persis pola penyetel, hanya dengan konvensi penamaan yang berbeda.
Ini seperti berpikir Anda menghindari jebakan para lajang dengan mengganti nama mereka menjadi satu-satunya yang bisa bertahan sambil menjaga implementasi yang sama.
sumber
Untuk mengubah
Customer
-class dari objek data, kita dapat bertanya pada diri sendiri pertanyaan berikut tentang bidang data:Bagaimana kita ingin menggunakan {data field}? Di mana {data field} digunakan? Bisakah dan haruskah penggunaan {data field} dipindahkan ke kelas?
Misalnya:
Apa tujuannya
Customer.Name
?Kemungkinan jawaban, tampilkan nama di halaman web login, gunakan nama dalam surat kepada pelanggan.
Yang mengarah ke metode:
Apa tujuannya
Customer.DOB
?Memvalidasi usia pelanggan. Diskon pada hari ulang tahun pelanggan. Surat
Mengingat komentar, objek contoh
Customer
- baik sebagai objek data dan sebagai objek "nyata" dengan tanggung jawabnya sendiri - terlalu luas; yaitu memiliki terlalu banyak properti / tanggung jawab. Yang mengarah ke banyak komponen tergantung padaCustomer
(dengan membaca propertinya) atauCustomer
bergantung pada banyak komponen. Mungkin ada pandangan pelanggan yang berbeda, mungkin masing-masing harus memiliki kelas 1 yang berbeda :Pelanggan dalam konteks
Account
dan transaksi moneter mungkin hanya digunakan untuk:Account
s.Pelanggan ini tidak perlu bidang seperti
DOB
,FavouriteColour
,Tel
, dan mungkin bahkan tidakAddress
.Pelanggan dalam konteks pengguna yang masuk ke situs web perbankan.
Bidang yang relevan adalah:
FavouriteColour
, yang mungkin datang dalam bentuk tema pribadi;LanguagePreferences
, danGreetingName
Alih-alih properti dengan getter dan setter, ini mungkin ditangkap dalam satu metode:
Pelanggan dalam konteks pemasaran dan pengiriman surat pribadi.
Di sini tidak mengandalkan properti dari suatu objek data, melainkan mulai dari tanggung jawab objek; misalnya:
Fakta bahwa objek pelanggan ini memiliki
FavouriteColour
properti, dan / atauAddress
properti menjadi tidak relevan: mungkin implementasinya menggunakan properti ini; tetapi mungkin juga menggunakan beberapa teknik pembelajaran mesin dan menggunakan interaksi sebelumnya dengan pelanggan untuk menemukan produk mana yang mungkin diminati pelanggan.1. Tentu saja,
Customer
danAccount
kelas adalah contoh, dan untuk contoh sederhana atau latihan pekerjaan rumah, memisahkan pelanggan ini mungkin berlebihan, tetapi dengan contoh pemisahan, saya berharap untuk menunjukkan bahwa metode mengubah objek data menjadi objek dengan tanggung jawab akan berhasil.sumber
Customer.FavoriteColor
?TL; DR
Pemodelan untuk perilaku itu baik.
Memodelkan abstraksi untuk kebaikan (!) Lebih baik.
Terkadang objek data diperlukan.
Perilaku dan Abstraksi
Ada beberapa alasan untuk menghindari getter dan setter. Salah satunya adalah, seperti yang Anda perhatikan, untuk menghindari pemodelan data. Ini sebenarnya adalah alasan kecil. Alasan yang lebih besar adalah untuk memberikan abstraksi.
Dalam contoh Anda dengan rekening bank yang jelas: Suatu
setBalance()
metode akan menjadi sangat buruk karena pengaturan saldo bukanlah tujuan penggunaan akun. Perilaku akun harus abstrak dari saldo saat ini sebanyak mungkin. Mungkin mempertimbangkan saldo ketika memutuskan apakah akan gagal melakukan penarikan, itu dapat memberikan akses ke saldo saat ini, tetapi memodifikasi interaksi dengan rekening bank seharusnya tidak mengharuskan pengguna untuk menghitung saldo baru. Itulah yang seharusnya dilakukan oleh akun itu sendiri.Bahkan sepasang
deposit()
danwithdraw()
metode tidak ideal untuk memodelkan rekening bank. Cara yang lebih baik adalah dengan menyediakan hanya satutransfer()
metode yang menggunakan akun lain dan jumlah sebagai argumen. Ini akan memungkinkan kelas akun untuk secara sepele memastikan bahwa Anda tidak secara tidak sengaja membuat / menghancurkan uang di sistem Anda, itu akan memberikan abstraksi yang sangat bermanfaat, dan itu benar-benar akan memberikan pengguna dengan lebih banyak wawasan karena akan memaksa penggunaan akun khusus untuk uang yang didapat / diinvestasikan / hilang (lihat akuntansi ganda ). Tentu saja, tidak setiap penggunaan akun membutuhkan tingkat abstraksi ini, tetapi jelas layak untuk mempertimbangkan berapa banyak abstraksi yang dapat diberikan oleh kelas Anda.Perhatikan bahwa menyediakan abstraksi dan menyembunyikan data internal tidak selalu sama. Hampir semua aplikasi berisi kelas yang hanya data secara efektif. Tuple, kamus, dan array adalah contoh yang sering. Anda tidak ingin menyembunyikan koordinat x suatu titik dari pengguna. Ada sangat sedikit abstraksi yang bisa / harus Anda lakukan dengan sebuah poin.
Kelas Pelanggan
Pelanggan jelas merupakan entitas dalam sistem Anda yang harus mencoba memberikan abstraksi yang bermanfaat. Sebagai contoh, itu kemungkinan harus dikaitkan dengan keranjang belanja, dan kombinasi dari keranjang dan pelanggan harus memungkinkan melakukan pembelian, yang mungkin memulai tindakan seperti mengirimnya produk yang diminta, membebankan biaya kepadanya (dengan mempertimbangkan pembayaran yang dipilihnya) metode), dll.
Tangkapannya adalah, bahwa semua data yang Anda sebutkan tidak hanya terkait dengan pelanggan, semua data itu juga bisa berubah. Pelanggan bisa pindah. Mereka dapat mengubah perusahaan kartu kredit mereka. Mereka dapat mengubah alamat email dan nomor telepon mereka. Heck, mereka bahkan dapat mengubah nama dan / atau jenis kelamin mereka! Jadi, kelas pelanggan berfitur lengkap memang harus menyediakan akses modifikasi penuh ke semua item data ini.
Namun, setter dapat / harus menyediakan layanan non-sepele: Mereka dapat memastikan format alamat email yang benar, verifikasi alamat pos, dll. Demikian juga, "pengambil" dapat menyediakan layanan tingkat tinggi seperti menyediakan alamat email dalam
Name <[email protected]>
format menggunakan bidang nama dan alamat email yang disetor, atau memberikan alamat pos yang diformat dengan benar, dll. Tentu saja, fungsi fungsional tingkat tinggi apa ini sangat tergantung pada kasus penggunaan Anda. Itu mungkin benar-benar berlebihan, atau mungkin memanggil kelas lain untuk melakukannya dengan benar. Pemilihan tingkat abstraksi tidak mudah.sumber
Mencoba mengembangkan jawaban Kasper, paling mudah untuk menentang dan menghilangkan setter. Dalam argumen yang agak kabur, handwaving (dan semoga lucu):
Kapan Pelanggan. Nama akan berubah?
Jarang. Mungkin mereka menikah. Atau pergi ke perlindungan saksi. Tetapi dalam hal ini Anda juga ingin memeriksa dan mungkin mengubah tempat tinggal mereka, keluarga terdekat, dan informasi lainnya.
Kapan DOB akan berubah?
Hanya saat pembuatan awal, atau pada entri entri data. Atau jika mereka adalah pemain baseball Domincan. :-)
Bidang-bidang ini tidak boleh diakses dengan setter rutin dan normal. Mungkin Anda memiliki
Customer.initialEntry()
metode, atauCustomer.screwedUpHaveToChange()
metode yang memerlukan izin khusus. Tetapi tidak memilikiCustomer.setDOB()
metode publik .Biasanya Pelanggan dibaca dari database, API REST, beberapa XML, apa pun. Memiliki metode
Customer.readFromDB()
, atau, jika Anda lebih tegas tentang SRP / pemisahan masalah, Anda akan memiliki pembangun yang terpisah, misalnyaCustomerPersister
objek denganread()
metode. Secara internal, mereka entah bagaimana mengatur bidang (Saya lebih suka menggunakan akses paket atau kelas dalam, YMMV). Tapi sekali lagi, hindari setter publik.(Tambahan sebagai Pertanyaan telah agak berubah ...)
Katakanlah aplikasi Anda banyak menggunakan basis data relasional. Akan bodoh memiliki
Customer.saveToMYSQL()
atauCustomer.readFromMYSQL()
metode. Itu menciptakan kopling yang tidak diinginkan ke entitas konkret, non-standar, dan cenderung berubah . Misalnya, ketika Anda mengubah skema, atau mengubah ke Postgress atau Oracle.Namun, IMO, itu bisa diterima untuk beberapa pelanggan ke standar abstrak ,
ResultSet
. Objek pembantu yang terpisah (saya akan menyebutnyaCustomerDBHelper
, yang mungkin merupakan subkelas dariAbstractMySQLHelper
) tahu tentang semua koneksi kompleks ke DB Anda, mengetahui detail optimasi rumit, mengetahui tabel, kueri, bergabung, dll ... (atau menggunakan ORM suka Hibernate) untuk menghasilkan ResultSet. Objek Anda berbicara keResultSet
, yang merupakan standar abstrak , tidak mungkin berubah. Saat Anda mengubah database yang mendasarinya, atau mengubah skema, Pelanggan tidak berubah , tetapi CustomerDBHelper berubah . Jika Anda beruntung, itu hanya AbstractMySQLHelper yang berubah yang secara otomatis membuat perubahan untuk Pelanggan, Merchant, Pengiriman dll ...Dengan cara ini Anda dapat (mungkin) menghindari atau mengurangi kebutuhan getter dan setter.
Dan, poin utama dari artikel Holub, membandingkan dan membedakan di atas dengan bagaimana jadinya jika Anda menggunakan getter dan setter untuk semuanya dan mengubah database.
Demikian pula, katakanlah Anda menggunakan banyak XML. IMO, tidak apa-apa untuk memasangkan Pelanggan Anda dengan standar abstrak, seperti Python xml.etree.ElementTree atau Java org.w3c.dom.Element . Pelanggan mendapatkan dan menetapkan sendiri dari itu. Sekali lagi, Anda dapat (mungkin) mengurangi kebutuhan getter dan setter.
sumber
Masalah memiliki getter dan setter dapat menjadi masalah fakta bahwa suatu kelas dapat digunakan dalam logika bisnis dalam satu cara tetapi Anda mungkin juga memiliki kelas pembantu untuk membuat serial / deserialisasi data dari database atau file atau penyimpanan persisten lainnya.
Karena faktanya ada banyak cara untuk menyimpan / mengambil data Anda dan Anda ingin memisahkan objek data dari cara mereka disimpan, enkapsulasi dapat "dikompromikan" dengan membuat anggota ini dipublikasikan, atau membuatnya dapat diakses melalui getter dan setter yang hampir sama buruknya dengan membuat mereka publik.
Ada berbagai cara untuk mengatasi hal ini. Salah satu caranya adalah membuat data tersedia untuk "teman". Meskipun pertemanan tidak diwariskan, ini dapat diatasi dengan serializer apa pun yang meminta informasi dari teman, yaitu serializer dasar "meneruskan" informasi tersebut.
Kelas Anda bisa menggunakan metode generik "fromMetadata" atau "toMetadata". From-metadata membangun objek jadi mungkin juga merupakan konstruktor. Jika itu adalah bahasa yang diketik secara dinamis, metadata cukup standar untuk bahasa seperti itu dan mungkin merupakan cara utama untuk membangun objek seperti itu.
Jika bahasa Anda khusus C ++, salah satu cara untuk mengatasi hal ini adalah dengan memiliki "struct" data publik dan kemudian untuk kelas Anda memiliki instance "struct" ini sebagai anggota dan pada kenyataannya semua data yang akan Anda simpan / ambil untuk disimpan di dalamnya. Anda kemudian dapat dengan mudah menulis "pembungkus" untuk membaca / menulis data Anda dalam berbagai format.
Jika bahasa Anda adalah C # atau Java yang tidak memiliki "struct" maka Anda dapat melakukan hal yang sama tetapi struct Anda sekarang menjadi kelas sekunder. Tidak ada konsep nyata "kepemilikan" dari data atau keteguhan jadi jika Anda memberikan contoh kelas yang berisi data Anda dan semuanya publik, apa pun yang ditahan dapat memodifikasinya. Anda bisa "mengkloningnya" walaupun ini bisa mahal. Atau Anda bisa membuat kelas ini memiliki data pribadi tetapi menggunakan accessor. Itu memberi pengguna kelas Anda cara bundaran untuk mendapatkan data tetapi itu bukan antarmuka langsung dengan kelas Anda dan benar-benar detail dalam menyimpan data kelas yang juga merupakan kasus penggunaan.
sumber
OOP adalah tentang merangkum dan menyembunyikan perilaku di dalam objek. Objek adalah kotak hitam. Ini adalah cara untuk mendesain sesuatu. Aset dalam banyak kasus seseorang tidak perlu mengetahui keadaan internal komponen lain dan lebih baik tidak harus mengetahuinya. Anda dapat menerapkan gagasan itu dengan antarmuka utama atau di dalam objek dengan visibilitas dan dengan hati-hati hanya verba / tindakan yang diizinkan yang tersedia untuk pemanggil.
Ini bekerja dengan baik untuk beberapa jenis masalah. Misalnya dalam antarmuka pengguna untuk memodelkan komponen UI individu. Ketika Anda berinteraksi dengan kotak teks, Anda hanya terputus dalam pengaturan teks, mendapatkannya atau mendengarkan acara perubahan teks. Anda biasanya tidak tertarik ke mana kursor berada, font yang digunakan untuk menggambar teks atau bagaimana keyboard digunakan. Enkapsulasi memberikan banyak hal di sini.
Sebaliknya ketika Anda memanggil layanan jaringan, Anda memberikan input eksplisit. Biasanya ada tata bahasa (seperti di JSON atau XML) dan semua opsi untuk memanggil layanan tidak memiliki alasan untuk disembunyikan. Idenya adalah bahwa Anda dapat memanggil layanan seperti yang Anda inginkan dan format data bersifat publik dan dipublikasikan.
Dalam hal ini, atau banyak lainnya (seperti akses ke database) Anda benar-benar bekerja dengan data bersama. Karena itu tidak ada alasan untuk menyembunyikannya, sebaliknya Anda ingin membuatnya tersedia. Mungkin ada kekhawatiran akses baca / tulis atau konsistensi datacheck tetapi pada inti ini, konsep inti jika ini adalah publik.
Untuk persyaratan desain seperti itu di mana Anda ingin menghindari enkapsulasi dan membuat hal-hal publik dan jelas, Anda ingin menghindari objek. Yang Anda butuhkan adalah tuple, struct C atau yang setara, bukan objek.
Tetapi itu juga terjadi dalam bahasa seperti Java, satu-satunya hal yang dapat Anda modelkan adalah objek atau array objek. Objek sendiri dapat menampung beberapa jenis asli (int, float ...) tapi itu saja. Tapi objek juga bisa berperilaku seperti struct sederhana hanya dengan bidang publik dan itu semua.
Jadi, jika Anda memodelkan data, Anda bisa melakukannya hanya dengan bidang publik di dalam objek karena Anda tidak perlu lagi. Anda tidak menggunakan enkapsulasi karena Anda tidak membutuhkannya. Ini dilakukan dengan cara ini dalam banyak bahasa. Dalam java, secara historis, standar naik di mana dengan pengambil / penyetel Anda setidaknya bisa memiliki kontrol baca / tulis (dengan tidak menambahkan penyetel misalnya) dan bahwa perkakas dan kerangka kerja dengan menggunakan instrospeksi API akan mencari metode pengambil / penyetel dan menggunakannya untuk Isi otomatis konten atau tampilkan tesis sebagai bidang yang dapat dimodifikasi di antarmuka pengguna yang dibuat secara otomatis.
Ada juga argumen Anda bisa menambahkan beberapa logika / memeriksa metode setter.
Pada kenyataannya hampir tidak ada pembenaran untuk pengambil / penentu karena mereka paling sering digunakan untuk memodelkan data murni. Kerangka kerja dan pengembang menggunakan objek Anda berharap pengambil / penyetel tidak melakukan apa-apa selain mengatur / mendapatkan bidang. Anda secara efektif tidak melakukan lebih banyak dengan pengambil / penyetel daripada apa yang bisa dilakukan dengan bidang publik.
Tapi itu kebiasaan lama dan kebiasaan lama sulit dihilangkan ... Anda bahkan bisa diancam oleh kolega atau guru Anda jika Anda tidak menempatkan getter / setter secara membabi buta di mana-mana jika mereka tidak memiliki latar belakang untuk lebih memahami apa mereka dan apa mereka tidak.
Anda mungkin perlu mengubah bahasa untuk mendapatkan semua kode getter / setter boilerplate ini. (Seperti C # atau lisp). Bagi saya pengambil / penyetel hanyalah kesalahan satu miliar dolar ...
sumber
@Getter @Setter class MutablePoint3D {private int x, y, z;}
.Saya pikir pertanyaan ini berduri karena Anda khawatir tentang metode perilaku untuk mengisi data tetapi saya tidak melihat indikasi perilaku apa yang
Customer
kelas objek dimaksudkan untuk merangkum.Jangan bingung
Customer
sebagai kelas objek dengan 'Pelanggan' sebagai pengguna / aktor yang melakukan tugas berbeda menggunakan perangkat lunak Anda.Ketika Anda mengatakan diberi kelas Pelanggan yang membuat banyak informasi tentang pelanggan maka sejauh perilaku kelihatannya kelas Pelanggan Anda memiliki sedikit membedakannya dari batu. A
Rock
dapat memiliki warna, Anda bisa memberinya nama, Anda bisa memiliki bidang untuk menyimpan alamatnya saat ini tetapi kami tidak mengharapkan segala macam perilaku cerdas dari batu.Dari artikel yang ditautkan tentang getter / setter menjadi jahat:
Tanpa perilaku yang didefinisikan, merujuk pada batu sebagai
Customer
tidak mengubah fakta bahwa itu hanya objek dengan beberapa properti yang ingin Anda lacak dan tidak masalah trik apa yang ingin Anda mainkan untuk menjauh dari getter dan setter. Batuan tidak peduli jika itu memiliki nama yang valid dan batu tidak akan diharapkan untuk mengetahui apakah alamat itu valid atau tidak.Sistem pesanan Anda dapat mengaitkan
Rock
dengan pesanan pembelian dan selama ituRock
memiliki alamat yang ditentukan maka beberapa bagian dari sistem dapat memastikan barang dikirim ke batu.Dalam semua kasus ini,
Rock
ini hanyalah Obyek Data dan akan terus menjadi objek sampai kita mendefinisikan perilaku spesifik dengan hasil yang bermanfaat alih-alih hipotesis.Coba ini:
Ketika Anda menghindari membebani kata 'Pelanggan' dengan 2 arti yang berpotensi berbeda, itu akan membuat segalanya lebih mudah untuk dikonsep.
Apakah
Rock
objek memesan atau apakah itu sesuatu yang dilakukan manusia dengan mengeklik elemen UI untuk memicu tindakan di sistem Anda?sumber
Saya menambahkan 2 sen saya di sini menyebutkan pendekatan objek yang berbicara SQL .
Pendekatan ini didasarkan pada gagasan objek mandiri. Ia memiliki semua sumber daya yang diperlukan untuk menerapkan perilakunya. Tidak perlu diberitahu bagaimana melakukan tugasnya - permintaan deklaratif sudah cukup. Dan suatu objek pasti tidak harus memegang semua datanya sebagai properti kelas. Ini benar-benar tidak - dan tidak seharusnya - masalah dari mana mereka berasal.
Berbicara tentang agregat , ketidakberubahan juga tidak menjadi masalah. Katakanlah, Anda memiliki urutan status yang dapat disimpan oleh agregat: Tidak apa-apa untuk menerapkan setiap status sebagai objek mandiri. Mungkin Anda bisa melangkah lebih jauh: ngobrol dengan pakar domain Anda. Kemungkinannya adalah bahwa dia tidak melihat agregat ini sebagai entitas yang disatukan. Mungkin setiap negara memiliki maknanya sendiri, layak mendapatkan objeknya sendiri.
Akhirnya, saya ingin mencatat bahwa proses pencarian objek sangat mirip dengan dekomposisi sistem menjadi subsistem . Keduanya didasarkan pada perilaku, bukan hal lain.
sumber