Latar Belakang
Saat ini saya memiliki situasi di mana saya memiliki objek yang dikirim dan diterima oleh perangkat. Pesan ini memiliki beberapa konstruk, sebagai berikut:
public void ReverseData()
public void ScheduleTransmission()
The ScheduleTransmission
Metode perlu untuk memanggil ReverseData
metode setiap kali disebut. Namun, ada saat-saat di mana saya perlu menelepon secara ReverseData
eksternal (dan saya harus menambahkan di luar namespace sepenuhnya ) dari mana objek tersebut dipakai dalam aplikasi.
Adapun "menerima" Maksud saya ReverseData
akan dipanggil secara eksternal dalam object_received
event-handler untuk membatalkan data.
Pertanyaan
Apakah secara umum dapat diterima suatu objek untuk memanggil metode publiknya sendiri?
c#
design-patterns
object-oriented
methods
Mengintip
sumber
sumber
Jawaban:
Saya akan mengatakan itu tidak hanya dapat diterima tetapi dianjurkan terutama jika Anda berencana untuk mengizinkan ekstensi. Untuk mendukung ekstensi ke kelas dalam C #, Anda perlu menandai metode sebagai virtual per komentar di bawah ini. Anda mungkin ingin mendokumentasikan ini, sehingga seseorang tidak terkejut ketika mengganti ReverseData () mengubah cara kerja ScheduleTransmission ().
Itu benar-benar bermuara pada desain kelas. ReverseData () terdengar seperti perilaku mendasar kelas Anda. Jika Anda perlu menggunakan perilaku ini di tempat lain, Anda mungkin tidak ingin memiliki versi lain. Anda hanya perlu berhati-hati agar Anda tidak membiarkan detail khusus untuk ScheduleTransmission () bocor ke dalam ReverseData (). Itu akan menciptakan masalah. Tetapi karena Anda sudah menggunakan ini di luar kelas, Anda mungkin sudah memikirkannya.
sumber
ReverseData()
abstrak, tidak peduli apa yang Anda lakukan di kelas anak, itu selalu merupakan metode asli yang akan dipanggil.virtual
... Dan jika Anda mengganti metode, maka menurut definisi itu harusvirtual
atauabstract
.virtual
bekerja juga. Dalam semua kasus, tanda tangan, menurut OP, adalahpublic void ReverseData()
, sehingga bagian dari jawaban tentang hal-hal utama sedikit menyesatkan.abstract
? Saya mencari jawaban padaabstract
vsvirtual
dan tidak melihat yang disebutkan: agak abstrak hanya berarti tidak ada versi yang diberikan dasar ini.Benar.
Visibilitas metode memiliki tujuan tunggal untuk mengizinkan atau menolak akses ke metode di luar kelas atau di dalam kelas anak; metode publik, terlindungi dan pribadi selalu dapat dipanggil di dalam kelas itu sendiri.
Tidak ada yang salah dalam memanggil metode publik. Ilustrasi dalam pertanyaan Anda adalah contoh sempurna dari situasi di mana memiliki dua metode publik persis apa yang harus Anda lakukan.
Namun, Anda dapat dengan cermat memperhatikan pola-pola berikut:
Metode
Hello()
memanggilWorld(string, int, int)
seperti ini:Hindari pola ini. Sebagai gantinya, gunakan argumen opsional . Argumen opsional membuat mudah ditemukan: pemanggil yang mengetik
Hello(
tidak perlu tahu bahwa ada metode yang memungkinkan untuk memanggil metode dengan nilai default. Argumen opsional juga mendokumentasikan diri.World()
tidak menunjukkan kepada pemanggil apa nilai default aktual.Metode
Hello(ComplexEntity)
memanggilWorld(string, int, int)
seperti ini:Sebaliknya, gunakan kelebihan beban . Alasan yang sama: kemampuan menemukan yang lebih baik. Penelepon dapat melihat sekaligus semua kelebihan beban melalui IntelliSense dan memilih yang benar.
Metode hanya memanggil metode publik lainnya tanpa menambahkan nilai substansial.
Berpikir dua kali. Apakah Anda benar-benar membutuhkan metode ini? Atau haruskah Anda menghapusnya dan membiarkan penelepon memanggil metode yang berbeda? Petunjuk: jika nama metode ini kelihatannya tidak benar atau sulit ditemukan, Anda mungkin harus menghapusnya.
Metode memvalidasi input dan kemudian memanggil metode lain:
Sebaliknya,
World
harus memvalidasi parameternya sendiri, atau bersifat pribadi.sumber
Jika sesuatu bersifat publik, itu dapat dipanggil kapan saja oleh sistem apa pun. Tidak ada alasan Anda tidak bisa menjadi salah satu dari sistem itu juga!
Di perpustakaan yang sangat optimal, Anda ingin menyalin idiom yang diajukan
java.util.ArrayList#ensureCapacity(int)
.PastikanKapasitas
ensureCapacity
bersifat publikensureCapacity
memiliki semua batas yang diperlukan memeriksa dan nilai default, dll.ensureCapacity
panggilanensureExplicitCapacity
memastikanKapasitasInternal
ensureCapacityInternal
bersifat pribadiensureCapacityInternal
memiliki pengecekan kesalahan minimal karena semua input berasal dari dalam kelasensureCapacityInternal
Panggilan JUGAensureExplicitCapacity
memastikanKapasitas Eksplisit
ensureExplicitCapacity
adalah JUGA pribadiensureExplicitCapacity
tidak memiliki pengecekan kesalahanensureExplicitCapacity
melakukan pekerjaan yang sebenarnyaensureExplicitCapacity
tidak dipanggil dari mana pun kecuali olehensureCapacity
danensureCapacityInternal
Dengan cara ini, kode yang Anda percayai mendapat akses istimewa (dan lebih cepat!) Karena Anda tahu inputnya baik. Kode yang tidak Anda percayai melewati kekakuan tertentu untuk memverifikasi integritasnya dan membom atau memberikan default atau menangani input yang buruk. Keduanya menyalurkan ke tempat yang benar-benar berfungsi.
Namun, ini digunakan di ArrayList, salah satu kelas yang paling banyak digunakan di JDK. Sangat mungkin kasing Anda tidak memerlukan tingkat kerumitan dan kekakuan itu. Singkat cerita, jika semua
ensureCapacityInternal
panggilan diganti denganensureCapacity
panggilan, kinerjanya masih akan sangat, sangat bagus. Ini adalah optimasi mikro mungkin hanya dilakukan setelah pertimbangan luas.sumber
Beberapa jawaban baik telah diberikan, dan saya juga akan setuju dengan mereka bahwa ya, suatu objek dapat memanggil metode publiknya dari metode lainnya. Namun, ada sedikit peringatan desain yang harus Anda perhatikan.
Metode publik biasanya memiliki kontrak "mengambil objek dalam keadaan konsisten, melakukan sesuatu yang masuk akal, meninggalkan objek dalam keadaan konsisten (mungkin berbeda)". Di sini, "konsisten" dapat berarti, misalnya, bahwa
Length
aList<T>
tidak lebih besar dari ituCapacity
dan yang mereferensikan unsur-unsur pada indeks dari0
keLength-1
tidak akan melempar.Tetapi di dalam metode objek, objek mungkin dalam keadaan tidak konsisten, jadi ketika Anda memanggil salah satu metode publik Anda, itu mungkin melakukan hal yang sangat salah, karena itu tidak ditulis dengan kemungkinan seperti itu dalam pikiran. Jadi, jika Anda berencana untuk memanggil metode publik Anda dari metode lain, pastikan bahwa kontrak mereka adalah "mengambil objek di beberapa negara, melakukan sesuatu yang masuk akal, meninggalkan objek dalam (mungkin berbeda) (mungkin tidak konsisten - tetapi hanya jika awal negara tidak konsisten) ".
sumber
Contoh lain ketika memanggil metode publik di dalam metode publik lain sama sekali baik-baik saja adalah pendekatan CanExecute / Execute. Saya menggunakannya ketika saya membutuhkan validasi dan pelestarian yang tidak berubah-ubah .
Tetapi secara umum saya selalu berhati-hati tentang itu. Jika suatu metode
a()
disebut metode dalamb()
, itu berarti metode tersebuta()
adalah detail implementasi darib()
. Sangat sering itu menunjukkan bahwa mereka termasuk level abstraksi yang berbeda. Dan fakta bahwa mereka berdua bersifat publik membuat saya bertanya-tanya apakah itu merupakan pelanggaran prinsip tanggung jawab tunggal atau tidak.sumber
Maaf, tetapi saya harus tidak setuju dengan sebagian besar jawaban 'ya Anda bisa' dan mengatakan bahwa:
Saya akan mencegah kelas memanggil satu metode publik dari yang lain
Ada beberapa masalah potensial dengan praktik ini.
1: Infinite loop di kelas yang diwarisi
Jadi kelas dasar Anda memanggil method1 dari method2 tetapi kemudian Anda, atau orang lain, mewarisi method1 dan menyembunyikan method1 dengan metode baru yang memanggil method2.
2: Acara, Pencatatan dll.
misal saya punya metode Add1 yang memancarkan suatu peristiwa '1 ditambahkan!' Saya mungkin tidak ingin metode Add10 meningkatkan kejadian itu, menulis ke log atau apa pun, sepuluh kali.
3: threading dan deadlock lainnya
Misalnya, InsertComplexData membuka koneksi db, memulai transaksi, mengunci tabel, Kemudian memanggil InsertSimpleData, dengan membuka koneksi, memulai transaksi, menunggu tabel dibuka ...
Saya yakin ada lebih banyak alasan, salah satu jawaban lain menyentuh 'Anda mengedit metode1 dan terkejut metode2 mulai berperilaku berbeda'
Secara umum, jika Anda memiliki dua metode publik yang berbagi kode, lebih baik membuat keduanya memanggil metode pribadi daripada satu panggilan yang lain.
Edit ----
Mari kita memperluas kasus khusus di OP.
kami tidak memiliki banyak detail tetapi kami tahu bahwa ReverseData dipanggil oleh event handler dari beberapa jenis serta metode ScheduleTransmission.
Saya berasumsi bahwa membalikkan data juga mengubah keadaan internal objek
Mengingat kasus ini, saya akan berpikir bahwa keselamatan utas akan menjadi penting dan karenanya keberatan ketiga saya terhadap praktik ini berlaku.
Untuk membuat thread ReverseData aman, Anda dapat menambahkan kunci. Tetapi jika ScheduleTransmission juga perlu diamankan, Anda ingin berbagi kunci yang sama.
Cara termudah untuk melakukan ini adalah dengan memindahkan kode ReverseData ke metode pribadi dan kedua metode publik menyebutnya. Anda kemudian dapat meletakkan pernyataan kunci di Metode Publik dan berbagi objek kunci.
Jelas Anda dapat berdebat "itu tidak akan pernah terjadi!" atau "Saya bisa memprogram kunci dengan cara lain" tetapi poin tentang praktik pengkodean yang baik adalah untuk menyusun kode Anda dengan baik sejak awal.
Dalam istilah akademis saya akan mengatakan ini melanggar huruf L dalam huruf padat. Metode publik lebih dari sekadar dapat diakses secara publik. Mereka juga dapat dimodifikasi oleh pewarisnya. Kode Anda harus ditutup untuk modifikasi yang berarti Anda harus memikirkan pekerjaan apa yang Anda lakukan baik dalam metode publik maupun yang dilindungi.
Inilah satu lagi: Anda juga berpotensi melanggar DDD. Jika objek Anda adalah objek domain, metode publiknya haruslah istilah Domain yang berarti sesuatu bagi bisnis. Dalam hal ini sangat tidak mungkin bahwa 'beli selusin telur' sama dengan 'beli 1 telur 12 kali' bahkan jika itu dimulai dengan cara itu.
sumber