ข้อความที่ส่งผ่านใน OO คืออะไร?


35

ฉันได้เรียนรู้การเขียนโปรแกรม OO เป็นหลักใน C ++, C # และ Java ฉันคิดว่าฉันมีความเข้าใจเป็นอย่างดีเกี่ยวกับความเข้าใจของฉันเกี่ยวกับการห่อหุ้มการสืบทอดและความหลากหลาย (รวมถึงการอ่านคำถามจำนวนมากบนไซต์นี้)

สิ่งหนึ่งที่ดูเหมือนจะปรากฏขึ้นที่นี่และมีแนวคิดของ "การส่งข้อความ" เห็นได้ชัดว่านี่คือสิ่งที่ไม่ได้ใช้ในขณะที่การเขียนโปรแกรม OO ในภาษาหลักของวันนี้ แต่ได้รับการสนับสนุนโดย Smalltalk

คำถามของฉันคือ:

  • ข้อความผ่านคืออะไร (มีคนให้ตัวอย่างที่เป็นประโยชน์ได้หรือไม่)
  • มีการสนับสนุน "ข้อความส่งผ่าน" นี้ใน C ++, C # หรือ Java หรือไม่

4
ฉันตอบคำถามนี้ไปแล้วเมื่อไม่นานมานี้: stackoverflow.com/a/3104741/10259
Frank Shearar

1
คุณอ่านบทความ Wikipedia แล้วหรือยัง?
yannis

4
ในความเห็นที่ต่ำต้อยของฉัน Objective-C น่าจะถือว่าเป็นภาษากระแสหลัก อย่างน้อยก็มากเท่ากับ C #
mouviciel

ฉันเห็นด้วยกับสิ่งนั้นฉันกำลังระบุภาษา "สำคัญ" จากประสบการณ์ของฉัน
Tom

ฟังก์ชั่นการเรียกสมาชิกเป็นหนึ่งในการดำเนินการผ่านข้อความ ข้อความที่ส่งผ่านจะถูกระบุด้วยชื่อฟังก์ชั่นและรวมถึงข้อมูลจากพารามิเตอร์ การรวมภายหลังช่วยให้คลาสที่ได้รับจัดการข้อความเดียวกันในวิธีที่แตกต่างไปยังคลาสอื่น ไม่ใช่สิ่งที่ตั้งใจไว้โดยผู้สร้าง Simula และหลาย ๆ คนจะโต้แย้งว่าการส่งข้อความและรัฐ (ด้วยเหตุผลที่ดี) ว่าการส่งข้อความเป็นสิ่งสำคัญที่ทำให้ Simula แตกต่างกัน แต่ฟังก์ชั่นสมาชิกยังคงเหมือนเดิม งาน.
Steve314

คำตอบ:


60

ข้อความผ่านคืออะไร (มีคนให้ตัวอย่างที่เป็นประโยชน์ได้หรือไม่)

ข้อความที่ผ่านก็หมายความว่า (ในระดับนามธรรมมาก) กลไกพื้นฐานของการทำงานของโปรแกรมคือวัตถุที่ส่งข้อความซึ่งกันและกัน จุดสำคัญคือชื่อและโครงสร้างของข้อความเหล่านี้ไม่จำเป็นต้องแก้ไขล่วงหน้าในซอร์สโค้ดและสามารถเป็นข้อมูลเพิ่มเติมได้ นี่เป็นส่วนสำคัญของสิ่งที่อลันเคย์มองว่า แต่เดิมคือ "การเขียนโปรแกรมเชิงวัตถุ"

มีการสนับสนุน "ข้อความส่งผ่าน" นี้ใน C ++, C # หรือ Java หรือไม่

ภาษาเหล่านี้ใช้ข้อความที่ จำกัด ผ่านการเรียกใช้เมธอด ถูก จำกัด เนื่องจากชุดข้อความที่สามารถส่งได้นั้น จำกัด เฉพาะวิธีที่ประกาศในคลาส ข้อดีของวิธีนี้คือสามารถใช้งานได้อย่างมีประสิทธิภาพมากและช่วยให้การวิเคราะห์โค้ดแบบสแตติกมีรายละเอียดมาก

ในทางกลับกันภาษาที่ส่งข้อความ "ของจริง" ที่ส่งผ่านมักจะมีข้อกำหนดของเมธอดด้วยเช่นกันซึ่งเป็นวิธีที่สะดวกในการใช้ตัวจัดการข้อความ แต่อนุญาตให้คลาสใช้ตัวจัดการข้อความที่มีความยืดหยุ่นมากขึ้น ในเวลารวบรวม)

เช่นใน Groovyที่แสดงให้เห็นถึงพลังของแนวคิดนี้:

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

จะสร้าง XML นี้:

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

โปรดทราบว่าrecords, car, countryและrecordมี syntactically วิธีการโทร MarkupBuilderแต่มีวิธีการของชื่อที่ไม่มีกำหนดไว้ใน แต่มีตัวจัดการข้อความ catchall ที่ยอมรับข้อความทั้งหมดและตีความชื่อข้อความเป็นชื่อขององค์ประกอบ XML พารามิเตอร์เป็นคุณลักษณะและปิดเป็นองค์ประกอบย่อย


+1 ตรงไปยังคำตอบของจุด ยอมรับตัวอย่างโค้ด ขอบคุณสำหรับความช่วยเหลือของคุณ :)
ทอม

ดังนั้นมันไม่สามารถนำไปใช้กับภาษาที่ง่ายsendMessage(property_name, Array of arguments)และgetMessage(property_name, Array of arguments)คงที่ได้หรือไม่?
Pacerier

1
@Pierier: แน่นอน แต่นั่นเป็นการรวมข้อเสียของทั้งสองวิธีเข้าด้วยกัน - คุณสูญเสียความปลอดภัยของประเภทและยังมี "sendMessage" ทำให้รหัสของคุณสกปรกทุกที่ดังนั้นคุณจะไม่ได้รับไวยากรณ์ที่หรูหรา
Michael Borgwardt

มันจะถูกต้องหรือไม่ที่จะบอกว่าในตัวอย่าง Groovy ตัวจัดการข้อความกำลังรับข้อความแทนที่จะเรียกเมธอด? ตอนแรกคุณใส่เครื่องหมายคำพูดล้อมรอบวลี "การเรียกเมธอด" แต่ในประโยคสุดท้ายของคุณคุณบอกว่ามัน "ยอมรับทุกวิธี " แทนที่จะเป็น "ข้อความ"
Adam Zerner

@ AdamZerner: ถูกต้องฉันแก้ไขแล้ว
Michael Borgwardt

28

การส่งข้อความเป็นวิธีที่แตกต่างในการจัดการความต้องการในรหัส OO สำหรับวัตถุหนึ่งเพื่อรับวัตถุอื่น (หรืออาจเป็นของตัวเอง) เพื่อทำบางสิ่งบางอย่าง

ในภาษาที่ทันสมัยที่สุดที่สืบทอดมาจากวิธี C ++ เราทำเช่นนั้นด้วยวิธีการโทร ในกรณีนี้อ็อบเจกต์ที่เรียกว่า (ผ่านการกำหนดคลาส) จะวางรายการใหญ่ ๆ ว่าเมธอดใดที่เรียกว่ามันยอมรับและจากนั้นตัวเข้ารหัสของออบเจ็กต์การเรียกก็เพียงแค่เขียนการเรียก:

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

สำหรับภาษาที่พิมพ์แบบคงที่แล้วคอมไพเลอร์สามารถตรวจสอบประเภทของสิ่งที่ถูกเรียกและยืนยันว่าวิธีการได้รับการประกาศ สำหรับภาษาที่พิมพ์แบบไดนามิกนั้นจะถูกดำเนินการตอนรันไทม์

แต่ในสาระสำคัญสิ่งที่เกิดขึ้นคือชุดของตัวแปรจะถูกส่งไปยังบล็อกรหัสเฉพาะ

ข้อความผ่าน

ในข้อความที่ผ่านภาษา (เช่น Objective C) แทนที่จะเป็นวิธีการมีผู้รับ แต่วิธีการกำหนดและเรียกพวกเขากว้างเหมือนกันมาก - ความแตกต่างคือวิธีการจัดการของมัน

ในข้อความที่ผ่านภาษาคอมไพเลอร์อาจตรวจสอบว่าผู้รับที่คุณเรียกว่ามีอยู่จริง แต่ที่แย่ที่สุดมันจะปรากฏขึ้นเพื่อเตือนว่าไม่แน่ใจว่ามีอยู่หรือไม่ นี่เป็นเพราะเวลาทำงานสิ่งที่จะเกิดขึ้นคือบล็อกของรหัสบนวัตถุที่รับจะถูกเรียกว่าผ่านทั้งชุดของตัวแปรและลายเซ็นของผู้รับที่คุณต้องการโทร บล็อกรหัสนั้นจะมองหาผู้รับและเรียกมันว่า อย่างไรก็ตามหากผู้รับไม่มีอยู่รหัสก็จะคืนค่าเริ่มต้น

ด้วยเหตุนี้หนึ่งในสิ่งประหลาดที่พบเมื่อย้ายจาก C ++ / Java -> Objective C คือการเข้าใจว่าคุณสามารถ "เรียกใช้เมธอด" บนวัตถุที่ไม่ได้ประกาศในเวลาคอมไพล์และไม่ได้มีอยู่บน ชนิดรันไทม์ ... และการโทรจะไม่ส่งผลให้เกิดข้อยกเว้นที่ถูกส่งออกไป แต่ในความเป็นจริงแล้วผลลัพธ์จะถูกส่งคืน

ข้อดีของวิธีนี้คือทำให้คลาสย่อยแบนราบและหลีกเลี่ยงความต้องการส่วนใหญ่สำหรับอินเตอร์เฟส / การสืบทอดหลายประเภท / เป็ด นอกจากนี้ยังอนุญาตให้วัตถุกำหนดพฤติกรรมเริ่มต้นเมื่อถูกขอให้ทำบางสิ่งที่ไม่มีผู้รับ (โดยทั่วไป "ถ้าฉันไม่ทำส่งคำขอไปยังวัตถุอื่นนี้") นอกจากนี้ยังสามารถลดความซับซ้อนของการเชื่อมโยงไปยังการเรียกกลับ (เช่นสำหรับองค์ประกอบ UI และเหตุการณ์ที่กำหนดเวลา) โดยเฉพาะอย่างยิ่งกับภาษาที่พิมพ์แบบคงที่เช่น Java (ดังนั้นคุณสามารถให้ปุ่มเรียกผู้รับ "runTest" แทนการเรียก "actionPerformed" "RunTestButtonListener" ซึ่งจะโทรหาคุณ)

อย่างไรก็ตามดูเหมือนว่าจะมีค่าใช้จ่ายที่จำเป็นสำหรับการตรวจสอบเพิ่มเติมโดยผู้พัฒนาว่าการโทรที่พวกเขาคิดว่าพวกเขากำลังทำอยู่บนวัตถุที่ถูกต้องด้วยประเภทที่ถูกต้องและผ่านพารามิเตอร์ที่เหมาะสมในลำดับที่ถูกต้องเพราะคอมไพเลอร์อาจไม่ เตือนคุณและมันจะทำงานได้อย่างสมบูรณ์แบบที่รันไทม์ (เพิ่งส่งคืนการตอบกลับเริ่มต้น) นอกจากนี้ยังมีเนื้อหาที่ได้รับผลกระทบจากการค้นหาพิเศษและการส่งผ่านพารามิเตอร์

วันนี้ภาษาที่พิมพ์แบบไดนามิกสามารถให้ประโยชน์มากมายกับข้อความที่ส่งผ่าน OO โดยมีปัญหาน้อยลง


1
ฉันชอบคำตอบนี้ - อธิบายความแตกต่างและความหมายของพวกเขา
HappyCat

@Gavin ดังนั้นจะเหมือนกับตัวจัดการวิธีการแบบไดนามิกของ PHP และ Javascript หรือไม่
Pacerier

11

สถาปัตยกรรมการส่งผ่านข้อความเป็นเพียงระบบที่แต่ละส่วนประกอบมีความเป็นอิสระจากคนอื่น ๆ ด้วยกลไกร่วมกันสำหรับการส่งผ่านข้อมูลระหว่างพวกเขา คุณสามารถพิจารณาการเรียกใช้เมธอดเป็นรูปแบบของการส่งข้อความ แต่ไม่สามารถทำได้เช่นกัน - มันทำให้เกิดความสับสน นี่เป็นเพราะถ้าคุณมีคลาสที่มีวิธีการที่กำหนดไว้อย่างดีและโค้ดบางอย่างที่เรียกเมธอดเหล่านั้นสิ่งทั้งหมดจะต้องถูกรวบรวมไว้ด้วยกันดังนั้นจึงเป็นการเชื่อมโยงรหัสและวัตถุเข้าด้วยกัน คุณสามารถดูว่ามันปิดอย่างไร (ขณะที่ข้อความกำลังถูกส่งผ่านและคอมไพเลอร์บังคับใช้ความถูกต้อง แต่มันสูญเสียความยืดหยุ่นของระบบที่แยกระบบออกเป็นส่วนใหญ่)

ข้อความที่ส่งผ่านสถาปัตยกรรมมักอนุญาตให้เพิ่มวัตถุในขณะใช้งานจริงและบ่อยครั้งที่ไม่อนุญาตให้มีการเปลี่ยนเส้นทางข้อความไปยังวัตถุอย่างน้อยหนึ่งรายการ ดังนั้นฉันจึงสามารถมีโค้ดที่เผยแพร่ข้อความ 'data x is updated' ให้กับวัตถุทั้งหมดที่ถูกโหลดเข้าสู่ระบบและแต่ละคนสามารถดำเนินการสิ่งที่พวกเขาต้องการกับข้อมูลนั้นได้

ตัวอย่างที่แปลกคือเว็บ HTTP เป็นระบบส่งข้อความ - คุณส่งคำสั่งกริยาและ 'data pack' ไปยังกระบวนการเซิร์ฟเวอร์ (เช่น GET http: \ myserver \ url) ทั้งเบราว์เซอร์ของคุณและเว็บเซิร์ฟเวอร์จะไม่สนใจข้อมูลที่คุณส่งหรือที่ที่คุณส่งไป เซิร์ฟเวอร์จะส่งต่อไปยังรหัสที่จะทำแพ็กเกจ 'แพ็คเก็ต' ของข้อมูลอื่นและส่งกลับมาให้คุณ ไม่มีส่วนประกอบใดในระบบนี้ที่รู้อะไรเกี่ยวกับสิ่งอื่น ๆ ที่ทำงานหรือสิ่งที่พวกเขาทำพวกเขาเพิ่งรู้ว่าโปรโตคอลที่ใช้สำหรับการสื่อสารข้อความ


@gbjbannb, Need คำอธิบายรหัสเทียมบาง ....
Pacerier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.