apa pesan yang lewat di OO?

35

Saya telah mempelajari pemrograman OO, terutama di C ++, C # dan Java. Saya pikir saya memiliki pemahaman yang baik tentangnya dengan pemahaman saya tentang enkapsulasi, pewarisan dan polimorfisme (serta membaca banyak pertanyaan di situs ini).

Satu hal yang sepertinya muncul di sana-sini adalah konsep "message passing". Rupanya, ini adalah sesuatu yang tidak digunakan saat pemrograman OO dalam bahasa arus utama saat ini, tetapi didukung oleh Smalltalk.

Pertanyaan saya adalah:

  • Apa yang lewat pesan? (Bisakah seseorang memberi contoh praktis?)
  • Apakah ada dukungan untuk "passing pesan" ini dalam C ++, C # atau Java?
Tom
sumber
4
Saya menjawab pertanyaan ini pada SO beberapa waktu lalu: stackoverflow.com/a/3104741/10259
Frank Shearar
1
Apakah Anda membaca artikel Wikipedia ?
yannis
4
Menurut pendapat saya yang sederhana, Objective-C akan memenuhi syarat sebagai bahasa utama. Setidaknya sebanyak C #.
mouviciel
Saya setuju dengan itu, saya menyatakan bahasa "arus utama" dari pengalaman saya
Tom
Panggilan fungsi anggota adalah salah satu implementasi dari menyampaikan pesan. Pesan yang dikirimkan diidentifikasi oleh nama fungsi, dan termasuk informasi dari parameter. Mengikat terlambat memungkinkan kelas penerima untuk menangani pesan yang sama dengan cara yang berbeda dengan kelas lainnya. Bukan itu yang dimaksudkan oleh pencipta Simula, dan banyak orang akan keberatan menyebutnya menyebutnya lewat pesan dan menyatakan (dengan alasan yang baik) bahwa melakukan pengiriman pesan adalah hal utama yang membuat Simula berbeda, tetapi panggilan fungsi anggota pada dasarnya tetap melakukan hal yang sama. pekerjaan.
Steve314

Jawaban:

60

Apa yang lewat pesan? (Bisakah seseorang memberi contoh praktis?)

Pesan yang lewat hanya berarti bahwa (pada tingkat yang sangat abstrak) mekanisme dasar pelaksanaan program adalah objek yang saling mengirim pesan. Poin penting adalah bahwa nama dan struktur pesan-pesan ini belum tentu diperbaiki sebelumnya dalam kode sumber dan itu sendiri dapat menjadi informasi tambahan. Ini adalah bagian penting dari apa yang Alan Kay awalnya bayangkan sebagai "pemrograman berorientasi objek".

Apakah ada dukungan untuk "passing pesan" ini dalam C ++, C # atau Java?

Bahasa ini menerapkan versi terbatas pesan yang melewati panggilan metode. Terbatas karena set pesan yang dapat dikirim terbatas pada metode yang dideklarasikan di kelas. Keuntungan dari pendekatan ini adalah dapat diimplementasikan dengan sangat efisien, dan memungkinkan analisis kode statis yang sangat terperinci (yang menghasilkan semua jenis manfaat yang bermanfaat, seperti penyelesaian kode).

Sebaliknya, bahasa yang menerapkan kelulusan pesan "nyata" sering memiliki definisi metode juga, sebagai cara yang nyaman untuk mengimplementasikan penangan pesan, tetapi memungkinkan kelas untuk mengimplementasikan penangan pesan yang lebih fleksibel yang memungkinkan objek menerima "panggilan metode" dengan nama sewenang-wenang (tidak diperbaiki pada waktu kompilasi).

Sebuah contoh dalam Groovy yang menunjukkan kekuatan konsep ini:

def xml = new MarkupBuilder(writer)
xml.records() {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
  }
}

akan menghasilkan XML ini:

<records>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'>Production Pickup Truck with speed of 271kph</record>
  </car>
</records>

Perhatikan bahwa records, car, countrydan recordsintaksis metode panggilan, tetapi tidak ada metode nama yang didefinisikan dalam MarkupBuilder. Sebaliknya, ia memiliki penangan pesan catchall yang menerima semua pesan dan menafsirkan nama pesan sebagai nama elemen XML, parameter sebagai atribut dan penutupan sebagai elemen anak.

Michael Borgwardt
sumber
+1 langsung ke jawaban langsung. Diterima untuk contoh kode. Terima kasih atas bantuan Anda :)
Tom
Jadi tidak bisakah hanya diimplementasikan dengan sederhana sendMessage(property_name, Array of arguments)dan getMessage(property_name, Array of arguments)dalam bahasa statis?
Pacerier
1
@ Peracerier: pasti, tapi itu menggabungkan kelemahan dari kedua pendekatan - Anda kehilangan keamanan jenis dan masih memiliki "sendMessage" yang mencemari kode Anda di mana-mana, sehingga Anda tidak mendapatkan sintaks yang elegan.
Michael Borgwardt
Apakah lebih tepat mengatakan bahwa, dalam contoh Groovy, penangan pesan menerima pesan, daripada pemanggilan metode? Anda awalnya memberi tanda kutip di sekitar frasa "pemanggilan metode", tetapi dalam kalimat terakhir, Anda mengatakan bahwa "menerima semua metode ", bukan "pesan".
Adam Zerner
@ AdamZerner: Anda benar, saya memperbaikinya.
Michael Borgwardt
28

Pesan yang lewat adalah cara berbeda dalam menangani kebutuhan dalam kode OO untuk satu objek untuk mendapatkan objek lain (atau berpotensi sendiri) untuk melakukan sesuatu.

Dalam sebagian besar bahasa modern yang berasal dari pendekatan C ++ kami melakukannya dengan pemanggilan metode. Dalam hal ini objek yang dipanggil (melalui definisi kelasnya) menempatkan daftar besar apa yang diterima metode dan kemudian pembuat kode dari objek yang memanggil hanya menulis panggilan:

public void doSomething ( String input )
...
other_object.dosomething ( local )

Untuk bahasa yang diketik secara statis maka kompiler kemudian dapat memeriksa jenis hal yang dipanggil dan mengonfirmasi bahwa metode telah dideklarasikan. Untuk bahasa yang diketik secara dinamis maka itu dilakukan pada saat runtime.

Tetapi pada dasarnya yang terjadi adalah bahwa kumpulan variabel dikirim ke blok kode tertentu.

Pesan lewat

Dalam bahasa lewat pesan (seperti Objective C) bukan metode ada penerima, tetapi secara luas pendekatan mendefinisikan mereka dan memanggil mereka hampir sama - perbedaannya adalah cara penanganannya.

Dalam pesan yang lewat bahasa, kompiler dapat memeriksa apakah penerima yang Anda panggil ada, tetapi paling buruk itu akan memunculkan peringatan untuk mengatakan bahwa tidak ada di sana. Ini karena pada saat run time yang akan terjadi adalah bahwa suatu blok kode pada objek penerima akan dipanggil lewat bundel variabel dan tanda tangan penerima yang ingin Anda panggil. Blok kode itu kemudian mencari penerima dan memanggilnya. Namun jika penerima tidak ada maka kode hanya akan mengembalikan nilai default.

Akibatnya salah satu keanehan yang ditemukan ketika pindah dari C ++ / Java -> Objective C adalah memahami bahwa Anda dapat "memanggil metode" pada objek yang tidak dideklarasikan pada tipe waktu kompilasi, dan bahkan tidak ada pada jenis run-time ... dan bahwa panggilan tidak akan menghasilkan pengecualian yang dilemparkan tetapi pada kenyataannya hasil yang dikembalikan.

Keuntungan dari pendekatan ini adalah bahwa hal itu meratakan hirarki subclass dan menghindari sebagian besar kebutuhan untuk antarmuka / beberapa jenis warisan / bebek. Ini juga memungkinkan objek untuk mendefinisikan perilaku default ketika diminta untuk melakukan sesuatu yang mereka tidak punya penerima (biasanya "jika saya tidak melakukannya, teruskan permintaan ke objek lain ini"). Itu juga dapat menyederhanakan penautan ke callback (misalnya untuk elemen UI dan peristiwa dengan waktu tertentu) terutama pada bahasa yang diketik secara statis seperti Java (sehingga Anda dapat meminta tombol memanggil penerima "runTest" daripada memanggil metode "actionPerformed" pada kelas dalam) "RunTestButtonListener" yang melakukan panggilan untuk Anda).

Namun tampaknya akan menjadi biaya dari kebutuhan untuk pemeriksaan tambahan oleh pengembang bahwa panggilan yang mereka pikir mereka lakukan adalah pada objek yang tepat dengan tipe yang tepat dan melewati parameter yang tepat dalam urutan yang benar, karena kompiler mungkin tidak memperingatkan Anda dan itu akan berjalan dengan baik saat runtime (hanya mengembalikan respons default). Ada juga bisa dibilang hit kinerja dari pencarian ekstra dan melewati paramter.

Saat ini, bahasa yang diketik secara dinamis dapat memberikan banyak manfaat dari pesan yang lulus OO dengan lebih sedikit masalah.

Gavin H
sumber
1
Saya suka jawaban ini - menjelaskan perbedaan dan implikasinya.
HappyCat
@ Gavin, jadi apakah itu persis sama dengan penangan metode dinamis PHP dan Javascript ?
Pacerier
11

Arsitektur passing pesan hanyalah sistem di mana setiap komponen tidak tergantung pada yang lain, dengan mekanisme umum untuk mengirimkan data di antara mereka. Anda dapat mempertimbangkan pemanggilan metode sebagai bentuk pengiriman pesan, tetapi tidak praktis untuk melakukannya - ini membingungkan masalah. Ini karena jika Anda memiliki kelas dengan metode yang terdefinisi dengan baik, dan beberapa kode yang memanggil metode tersebut, keseluruhannya harus dikompilasi bersama, sehingga menyatukan kode dan objek. Anda dapat melihat seberapa dekat (saat pesan dikirimkan, dan kompiler menegakkan kebenaran, tetapi ia kehilangan banyak fleksibilitas dari sistem yang dipisahkan).

Arsitektur lewat pesan sering memungkinkan objek untuk ditambahkan saat runtime, dan lebih sering daripada tidak memungkinkan pesan untuk diarahkan ke satu atau lebih objek. Jadi saya dapat memiliki beberapa kode yang menyiarkan pesan 'data x diperbarui' ke semua objek yang telah dimuat ke dalam sistem, dan masing-masing dari mereka dapat mengambil tindakan apa pun yang mereka suka dengan informasi itu.

Contoh aneh adalah web. HTTP adalah sistem penyampaian pesan - Anda melewatkan kata kerja perintah dan 'paket data' ke proses server. (mis. DAPATKAN http: \ myserver \ url) Baik browser Anda, maupun server web tidak peduli apa pun tentang data yang Anda kirim, atau ke mana Anda mengirimnya. Server akan meneruskannya ke kode yang akan mengemas 'paket' data lain dan mengirimkannya kembali kepada Anda. Tidak ada komponen dalam sistem ini yang tahu apa-apa tentang pekerjaan orang lain atau apa yang mereka lakukan, mereka hanya tahu protokol yang digunakan untuk komunikasi pesan.

gbjbaanb
sumber
@ gbjbannb, Butuh penjelasan kode pseudo ....
Pacerier