OO’da geçen mesaj nedir?


35

OO programcılığı okuyorum, öncelikle C ++, C # ve Java. Kapsülleme, kalıtım ve polimorfizm anlayışı ile (bu sitede pek çok soru okuduğumda) anladım.

Burada açılan ve görünen bir şey var "mesaj geçiyor" kavramı. Görünüşe göre, bu günümüzün ana dillerinde OO programlaması yaparken kullanılmayan, ancak Smalltalk tarafından desteklenen bir şeydir.

Benim sorularım:

  • Mesaj geçme nedir? (Birisi pratik bir örnek verebilir mi?)
  • C ++, C # veya Java dilinde bu "mesaj iletme" için herhangi bir destek var mı?

4
Bu soruyu
SO'da


4
Benim düşünceme göre, Objective-C, ana dil olarak nitelenir. En azından C # kadar.
moouviciel

Kabul ediyorum, tecrübelerime dayanarak "ana" dilleri belirttim
Tom

Üye işlev çağrısı, mesaj iletmenin bir uygulamasıdır. İletilen mesaj, fonksiyon ismi ile tanımlanır ve parametrelerdeki bilgileri içerir. Geç bağlama, alıcı sınıfın aynı mesajı diğer sınıflara göre farklı bir şekilde ele almasını sağlar. Simula'nın yaratıcıları tarafından amaçlanan bu değildi ve birçok kişi mesaj iletmek için itirazda bulunacak ve mesaj gönderme yapmanın Simula'yı farklı kılan önemli bir şey olduğunu belirtmiş, ancak üye işlev çağrıları esasen aynı şeyi yapmıştır. iş.
Steve314

Yanıtlar:


60

Mesaj geçme nedir? (Birisi pratik bir örnek verebilir mi?)

İleti iletmek, basit bir şekilde (çok soyut bir düzeyde) program yürütmenin temel mekanizmasının birbirlerini ileten nesneler olduğu anlamına gelir. Önemli olan nokta, bu mesajların adının ve yapısının kaynak kodunda önceden sabit olması gerekmediği ve ek bilgi olabileceğidir. Bu Alan Kay'ın aslında "nesne yönelimli programlama" olarak öngördüğü şeyin önemli bir parçasıdır.

C ++, C # veya Java dilinde bu "mesaj iletme" için herhangi bir destek var mı?

Bu dil, yöntem çağrılarından geçen sınırlı bir mesaj sürümü uygular. Sınırlı çünkü gönderilebilecek mesaj kümesi bir sınıfta bildirilen yöntemlerle sınırlıdır. Bu yaklaşımın avantajı, çok verimli bir şekilde uygulanabilmesi ve çok ayrıntılı statik kod analizini mümkün kılmasıdır (kod tamamlama gibi her türlü yararlı fayda ile sonuçlanır).

Tersine, "gerçek" iletiyi iletmeyi uygulayan diller genellikle ileti işleyicilerini uygulamanın uygun bir yolu olarak yöntem tanımlarına da sahiptir, ancak sınıfların nesnenin rasgele adlarla "yöntem çağrıları" almasını sağlayan daha esnek ileti işleyicileri uygulamalarına izin vermez (sabit değil) derleme zamanında).

Groovy'de bu kavramın gücünü gösteren bir örnek :

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')
  }
}

bu XML'i üretecek:

<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>

Not records, car, countryve recordsözdizimsel yöntem çağrıları, ama tanımlanan bu ismin bir yöntem bulunmamaktadır MarkupBuilder. Bunun yerine, tüm iletileri kabul eden ve ileti adlarını bir XML öğesinin adı, parametreleri nitelendiren parametreler ve alt öğeler olarak kapatan bir yorum yazıcısı işleyicisine sahiptir.


+1 doğrudan nokta cevabına. Kod örneği için kabul edildi. Yardımınız için teşekkürler :)
Tom

Öyleyse basit sendMessage(property_name, Array of arguments)ve getMessage(property_name, Array of arguments)statik dillerde basitçe uygulanamaz mıydı?
Pacerier

1
@Pacerier: elbette, ancak bu her iki yaklaşımın dezavantajlarını birleştiriyor - tür güvenliğini kaybediyorsunuz ve hala kodunuzu kirleten "sendMessage" kullanıyorsunuz, bu yüzden zarif sözdizimini alamadınız.
Michael Borgwardt

Groovy örneğinde, ileti işleyicisinin bir yöntem çağrısı yerine bir ileti aldığını söylemek daha doğru olur mu? Başlangıçta "yöntem çağrısı" ifadesinin etrafında alıntılar koyarsınız, ancak son cümlenizde "iletiler" yerine " tüm yöntemleri kabul edersiniz" diyorsunuz .
Adam Zerner

@AdamZerner: Haklısın, tamir ettim.
Michael Borgwardt

28

İleti iletme, bir nesnenin başka bir nesneyi (veya potansiyel olarak kendisinin) bir şeyi yapması için OO kodundaki ihtiyacı ele almanın farklı bir yoludur.

C ++ yaklaşımından çıkan çoğu modern dilde bunu metod çağrıları ile yapıyoruz. Bu durumda, çağrılan nesne (sınıf tanımı aracılığıyla), kabul ettiği yöntemin kabul ettiği yöntemlerin büyük bir listesini koyar ve ardından arayan nesnenin kodlayıcısı çağrıyı yalnızca yazar:

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

Statik olarak yazılmış diller için derleyici daha sonra çağrılan şeyin türünü kontrol edebilir ve yöntemin bildirildiğini onaylayabilir. Dinamik olarak yazılmış diller için o zaman çalışma zamanında gerçekleştirilir.

Fakat özünde olan şey, bir paket değişkeninin belirli bir kod bloğuna gönderildiğidir.

İleti geçişi

Mesaj yerine geçen dillerde (örneğin, C nesnesindeki gibi) yöntemler yerine alıcılar vardır, fakat genel olarak onları tanımlama ve onları çağırma yaklaşımı aynıdır - fark, işlenme şeklidir.

Bir mesajın geçtiği dilde, derleyici aradığınız alıcının var olup olmadığını kontrol edebilir , ama en kötüsü orada olduğundan emin olmadığını söylemek için bir uyarı çıkarır. Bunun nedeni, çalışma zamanında gerçekleşecek olan şey, alıcı değişken üzerindeki bir kod bloğunun hem değişken paketini hem de aramak istediğiniz alıcının imzasını geçerek çağrılmasıdır. Bu kod bloğu daha sonra alıcıyı arar ve onu çağırır. Ancak alıcı yoksa, kod basitçe varsayılan bir değer döndürür.

Sonuç olarak, C ++ / Java -> Objective C konumundan taşınırken ortaya çıkan tuhaflıklardan biri, derleme zamanı türünde bildirilmemiş ve üzerinde bulunmayan bir nesnede "yöntem çağırabileceğinizi" anlamaktır. çalışma zamanı türü ... ve çağrının bir istisna atılmasına neden olamayacağı, gerçekte bir sonucun geri alınacağı sonucuna varır.

Bu yaklaşımın avantajları, alt sınıf sıradüzenini düzleştirmesi ve arayüzler / çoklu kalıtım / ördek türleri için ihtiyaçların çoğundan kaçınmasıdır. Ayrıca, alıcıları olmayan bir şey yapmaları istendiğinde nesnelerin varsayılan davranışı tanımlamasına olanak tanır (genellikle "yapmazsam, isteği bu diğer nesneye ilet"). Ayrıca, özellikle Java gibi statik olarak yazılmış diller üzerinden geri aramalara (örneğin, UI öğeleri ve zamanlanmış olaylar için) bağlantı yapılmasını basitleştirebilir (böylece, düğmeye, iç sınıftaki "actionPerformed" yöntemini çağırmak yerine "runTest" alıcısını çağırma şansı verebilir. "RunTestButtonListener" sizin için arama yapar).

Bununla birlikte, geliştirici tarafından yaptıkları çağrının doğru tipte ve doğru parametreleri doğru sırayla geçirerek doğru nesne üzerinde olduğunu ve ek parametreleri doğru sırayla geçirdiğini düşündüğü için ek kontrol gereksinimine mal olacak gibi görünmektedir. sizi uyarır ve çalışma zamanında mükemmel çalışır (sadece varsayılan bir cevap döndürür). Muhtemelen, ekstra görünüm ve paramter geçişinden elde edilen bir performans vuruşu da var.

Bu gün, dinamik olarak yazılmış diller, daha az sorunla OO’dan geçen mesajın birçok faydasını sağlayabilir.


1
Bu cevabı beğendim - farklılıkları ve bunların sonuçlarını açıklar.
HappyCat

@ Gavin, Peki PHP ve Javascript'in dinamik yöntem işleyicisi ile tamamen aynı mı?
Pacerier

11

Mesaj iletme mimarileri, her bir bileşenin diğerlerinden bağımsız olduğu, aralarında veri iletilmesi için ortak bir mekanizma bulunan sistemlerdir. Metot çağrılarını bir mesaj iletme şekli olarak düşünebilirsiniz, ancak bunu yapmak pratik değil - konuyu karıştırır. Bunun nedeni, iyi tanımlanmış metotlara sahip bir sınıfa ve bu metotları çağıran bazı kodlara sahipseniz, her şeyin birlikte derlenmesi gerekir, böylece kodu ve nesneyi birleştiririz. ne kadar yakın olduğunu görebilirsiniz (bir mesaj iletilirken ve derleyici doğruluğu zorluyor, fakat ayrık bir sistemin esnekliğinin çoğunu kaybediyor).

İleti iletme mimarileri genellikle nesnelerin çalışma zamanında eklenmesine izin verir ve iletilerin bir veya daha fazla nesneye yönlendirilmesine izin vermemektansa daha sık kullanılır. Böylece sisteme yüklenen tüm nesnelere 'veri x güncellendi' mesajını yayınlayan bir kod bulabilirim ve her biri bu bilgilerle istedikleri her şeyi yapabilir.

Tuhaf bir örnek web. HTTP bir mesaj iletme sistemidir - bir sunucu işlemine bir komut fiili ve bir 'veri paketi' iletirsiniz. (örn. GET http: \ myserver \ url) Ne tarayıcınız ne de web sunucusu gönderdiğiniz veriler veya nereye gönderdiğiniz hakkında hiçbir şey umursamıyor. Sunucu, başka bir 'veri' paketini paketleyecek ve size geri gönderecek olan koda iletecektir. Bu sistemdeki bileşenlerin hiçbiri diğerlerinin çalışması veya ne yaptıkları hakkında hiçbir şey bilmiyor, sadece mesaj iletişimi için kullanılan protokolü biliyorlar.


@gbjbannb, Sözde kod açıklamalarına ihtiyacım var ....
Pacerier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.