บทคัดย่อ: บทความนี้จะกล่าวถึงแนวคิดของความหลากหลายและการประยุกต์ในการออกแบบเชิงวัตถุ นอกจากนี้ ยังจะวิเคราะห์วิธีใช้ความหลากหลายใน PHP 5 ตลอดจนข้อดีและข้อเสียของมัน
มีการรองรับการผูกล่าช้าใน PHP รุ่นล่าสุด แน่นอนว่ายังคงมีปัญหามากมายเมื่อใช้ฟังก์ชันการรวมล่าช้า หากคุณใช้ PHP เวอร์ชันเก่า (เซิร์ฟเวอร์ของฉันใช้งาน PHP 5.0.1) คุณอาจพบว่ายังขาดการรองรับการเชื่อมโยงล่าช้า ดังนั้น โปรดทราบว่าโค้ดในบทความนี้อาจไม่ทำงานใน PHP 5 เวอร์ชันเฉพาะของคุณ
1. PHP 5 และ Polymorphism
บทความนี้จะอภิปรายถึงส่วนที่สำคัญที่สุดประการหนึ่งของการเขียนโปรแกรมเชิงวัตถุ - การออกแบบความหลากหลาย เพื่ออธิบายปัญหา ฉันใช้ PHP 5 ก่อนที่คุณจะอ่านต่อ โปรดชี้แจงให้ชัดเจนว่าบทความนี้ไม่ได้เกี่ยวกับ PHP ทั้งหมด แม้ว่าภาษาจะมีความก้าวหน้าอย่างมากในการพัฒนาอย่างรวดเร็วในสองเวอร์ชันหลักที่ผ่านมา แต่การรองรับออบเจ็กต์ยังคงมีเวลาอีกระยะหนึ่งก่อนที่จะสามารถแข่งขันกับภาษาที่เป็นผู้ใหญ่มากกว่าเช่นหลักสูตร C ++ หรือ Java
หากคุณเป็นมือใหม่ในการเขียนโปรแกรมเชิงวัตถุ บทความนี้อาจไม่เหมาะกับคุณ เนื่องจากส่วนนี้ของความหลากหลายมีความพิเศษ: เมื่อคุณเข้าใจแล้ว คุณจะไม่มีวันลืมมัน หากคุณต้องการเรียนรู้เล็กน้อยเกี่ยวกับการเขียนโปรแกรมและการออกแบบวัตถุ และคุณไม่รู้ว่ามันหมายถึงอะไรเมื่อมีคนพูดว่า "วัตถุนั้นมีความหลากหลาย" บทความนี้เหมาะสำหรับคุณ
ในตอนท้ายของบทความนี้ คุณควรรู้ว่าความหลากหลายคืออะไร และจะนำไปใช้กับการออกแบบเชิงวัตถุได้อย่างไร และคุณจะเข้าใจข้อดีและข้อเสียของการเขียนโปรแกรมวัตถุใน PHP 5
2. ความหลากหลายคืออะไร?
คำจำกัดความของความหลากหลายจาก Dictionary.com คือ "เกิดขึ้นในรูปแบบ ระยะ หรือประเภทที่แตกต่างกันในองค์กรอิสระหรือในองค์กรเดียวกันโดยไม่มีความแตกต่างพื้นฐาน" จากคำจำกัดความนี้ เราสามารถคิดได้ว่าความหลากหลายทางเพศเป็นวิธีการเขียนโปรแกรมในการอธิบายสิ่งเดียวกัน วัตถุผ่านหลายสถานะหรือเฟส ที่จริงแล้ว ความหมายที่แท้จริงของมันคือในการพัฒนาจริง เราเพียงแต่ต้องมุ่งเน้นไปที่การเขียนโปรแกรมของอินเทอร์เฟซหรือคลาสพื้นฐาน และไม่ต้องกังวลกับคลาส (คลาส) เฉพาะที่วัตถุนั้นอยู่
หากคุณคุ้นเคยกับรูปแบบการออกแบบ แม้ว่าคุณจะมีความเข้าใจเบื้องต้น แต่คุณก็จะเข้าใจแนวคิดนี้ ในความเป็นจริง ความหลากหลายอาจเป็นเครื่องมือที่ดีที่สุดในการเขียนโปรแกรมการออกแบบตามรูปแบบ ช่วยให้เราสามารถจัดระเบียบวัตถุที่คล้ายกันในลักษณะที่เป็นตรรกะเพื่อที่เราจะได้ไม่ต้องกังวลเกี่ยวกับประเภทของวัตถุเฉพาะเมื่อเขียนโค้ด ยิ่งกว่านั้น เราจำเป็นต้องเขียนโปรแกรมอินเทอร์เฟซหรือคลาสพื้นฐานที่ต้องการเท่านั้น ยิ่งแอปพลิเคชันมีความเป็นนามธรรมมากเท่าไรก็ยิ่งมีความยืดหยุ่นมากขึ้นเท่านั้น และความหลากหลายก็เป็นหนึ่งในวิธีที่ดีที่สุดในการใช้พฤติกรรมแบบนามธรรม
ตัวอย่างเช่น ลองพิจารณาคลาสที่เรียกว่า Person เราสามารถซับคลาสบุคคลได้ด้วยคลาสที่เรียกว่า David, Charles และ Alejandro บุคคลมีวิธีนามธรรม AcceptFeedback() และคลาสย่อยทั้งหมดต้องใช้วิธีนี้ ซึ่งหมายความว่าโค้ดใดๆ ที่ใช้คลาสย่อยของคลาส Person พื้นฐานสามารถเรียกใช้เมธอด AcceptFeedback() ได้ คุณไม่จำเป็นต้องตรวจสอบว่าวัตถุนั้นเป็นเดวิดหรืออเลฮานโดร แค่รู้ว่าเป็นบุคคลก็เพียงพอแล้ว ด้วยเหตุนี้ รหัสของคุณจะต้องเน้นไปที่ "ตัวส่วนร่วมที่ต่ำที่สุด" เท่านั้น - คลาส Person
คลาส Person ในตัวอย่างนี้สามารถสร้างเป็นอินเทอร์เฟซได้ แน่นอนว่ามีความแตกต่างบางประการเมื่อเทียบกับข้างต้น โดยหลักๆ แล้ว อินเทอร์เฟซไม่ได้ให้พฤติกรรมใดๆ แต่กำหนดเพียงชุดของกฎเท่านั้น อินเทอร์เฟซ Person ต้องการ "คุณต้องรองรับเมธอด AddFeedback()" ในขณะที่คลาส Person สามารถให้โค้ดเริ่มต้นบางส่วนสำหรับเมธอด AddFeedback() ได้ - ความเข้าใจของคุณเกี่ยวกับสิ่งนี้อาจเป็น "ถ้าคุณไม่เลือกที่จะรองรับ AddFeedback() ดังนั้น คุณควรจัดให้มีการใช้งานเริ่มต้น "วิธีการเลือกอินเทอร์เฟซหรือคลาสพื้นฐานอยู่นอกเหนือหัวข้อของบทความนี้ อย่างไรก็ตาม โดยทั่วไป คุณจะต้องใช้วิธีการเริ่มต้นผ่านคลาสพื้นฐาน คุณยังสามารถใช้อินเทอร์เฟซได้ หากคุณสามารถร่างชุดฟังก์ชันการทำงานที่ต้องการซึ่งชั้นเรียนของคุณนำไปใช้ได้
3. การใช้การออกแบบโพลีมอร์ฟิก
เราจะใช้ตัวอย่างของคลาสฐานบุคคลต่อไป และตอนนี้เราจะวิเคราะห์การใช้งานที่ไม่ใช่โพลีมอร์ฟิก ตัวอย่างต่อไปนี้ใช้อ็อบเจ็กต์ Person ประเภทต่างๆ ซึ่งเป็นวิธีการเขียนโปรแกรมที่ไม่น่าพอใจอย่างยิ่ง โปรดทราบว่าคลาส Person ที่แท้จริงจะถูกละเว้น จนถึงตอนนี้ เรากังวลเฉพาะกับปัญหาการเรียกรหัสเท่านั้น
<?php
$name = $_SESSION['ชื่อ'];
$myPerson = บุคคล::GetPerson($ชื่อ);
สวิตช์ (get_class($myPerson)){
กรณี 'เดวิด' :
$myPerson->AddFeedback('บทความดีๆ!', 'ผู้อ่านบางคน', date('Ym-d'));
หยุดพัก;
กรณี 'ชาร์ลส์':
$myPerson->feedback[] = array('ผู้อ่านบางคน', 'การแก้ไขยอดเยี่ยม!');
หยุดพัก;
กรณี 'อเลฮานโดร' :
$myPerson->ข้อเสนอแนะ->ผนวก('จาวาสคริปต์ที่ยอดเยี่ยม!');
หยุดพัก;
ค่าเริ่มต้น :
$myPerson->AddFeedback('เย้!');
-
?>
ตัวอย่างนี้แสดงออบเจ็กต์ที่มีพฤติกรรมต่างกัน และคำสั่ง switch ใช้เพื่อแยกแยะอ็อบเจ็กต์คลาส Person ที่แตกต่างกันเพื่อดำเนินการที่ถูกต้องตามลำดับ โปรดทราบว่าความคิดเห็นคำติชมที่นี่จะแตกต่างกันไปตามเงื่อนไขที่แตกต่างกัน นี่อาจไม่ใช่กรณีในการพัฒนาแอปพลิเคชันจริง ฉันเพียงแค่แสดงให้เห็นความแตกต่างที่มีอยู่ในการใช้งานคลาส
ตัวอย่างด้านล่างใช้ความหลากหลาย
<?php
$name = $_SESSION['ชื่อ'];
$myPerson = บุคคล::GetPerson($ชื่อ);
$myPerson->AddFeedback('บทความดีๆ!', 'SomeReader', date('Ym-d'));
?>
โปรดทราบว่าไม่มีคำสั่ง switch ที่นี่ และที่สำคัญที่สุด ยังขาดข้อมูลเกี่ยวกับประเภทของวัตถุที่ Person::GetPerson() จะกลับมา และอีกบุคคล::AddFeedback() เป็นวิธีการแบบ polymorphic พฤติกรรมถูกห่อหุ้มไว้อย่างสมบูรณ์โดยคลาสที่เป็นรูปธรรม จำไว้ว่าไม่ว่าเราจะใช้ David, Charles หรือ Alejandro ที่นี่ Calling Code ไม่จำเป็นต้องรู้ว่า Concrete Class ทำอะไร มีเพียงคลาสพื้นฐานเท่านั้น
แม้ว่าตัวอย่างของฉันจะไม่สมบูรณ์แบบ แต่ก็แสดงให้เห็นถึงการใช้งานพื้นฐานของความหลากหลายจากมุมมองของรหัสการโทร ตอนนี้เราจำเป็นต้องวิเคราะห์การใช้งานภายในของคลาสเหล่านี้ สิ่งที่ยอดเยี่ยมอย่างหนึ่งเกี่ยวกับการได้รับมาจากคลาสพื้นฐานคือคลาสที่ได้รับสามารถเข้าถึงพฤติกรรมของคลาสพาเรนต์ได้ ซึ่งมักจะเป็นการใช้งานเริ่มต้น แต่อาจเกิดขึ้นในสายโซ่การสืบทอดคลาสเพื่อสร้างพฤติกรรมที่ซับซ้อนมากขึ้น ด้านล่างนี้เป็นการสาธิตอย่างง่าย ๆ เกี่ยวกับสถานการณ์นี้
<?php
บุคคลในชั้นเรียน{
ฟังก์ชั่น AddFeedback($comment, $sender, $date){
//เพิ่มข้อเสนอแนะไปยังฐานข้อมูล}
-
คลาสเดวิดขยายบุคคล{
ฟังก์ชั่น AddFeedback($comment, $sender){
parent::AddFeedback($ความคิดเห็น, $sender,
วันที่('Ym-d'));
-
-
?>
ในที่นี้ เมธอด Person::AddFeedback จะถูกเรียกเป็นครั้งแรกในการใช้งานเมธอด AddFeedback ในคลาส David คุณอาจสังเกตเห็นว่ามันเลียนแบบวิธีการโอเวอร์โหลดใน C ++, Java หรือ C # โปรดทราบว่านี่เป็นเพียงตัวอย่างง่ายๆ และโค้ดจริงที่คุณเขียนนั้นขึ้นอยู่กับโปรเจ็กต์จริงของคุณโดยสิ้นเชิง
4. การผูกล่าช้าใน PHP 5
ในความคิดของฉัน การผูกล่าช้าเป็นเหตุผลสำคัญว่าทำไม Java และ C# จึงน่าสนใจมาก อนุญาตให้เมธอดคลาสพื้นฐานเรียกใช้เมธอดโดยใช้ "this" หรือ $this (แม้ว่าจะไม่มีอยู่ในคลาสพื้นฐานหรือการเรียกเมธอดในคลาสพื้นฐานก็อาจถูกแทนที่ด้วยเวอร์ชันอื่นในคลาสที่สืบทอดมา) คุณสามารถพิจารณาการใช้งานต่อไปนี้ที่จะได้รับอนุญาตใน PHP:
<?php
บุคคลในชั้นเรียน{
ฟังก์ชั่น AddFeedback($messageArray) {
$this->ParseFeedback($messageArray);
//เขียนลงฐานข้อมูล}
-
คลาสเดวิดขยายบุคคล{
ฟังก์ชั่น ParseFeedback($messageArray){
// ทำการวิเคราะห์บ้าง}
-
?>
จำไว้ว่าไม่มี ParseFeedback ในคลาส Person ตอนนี้ สมมติว่าคุณมีโค้ดการใช้งานส่วนนี้ (เพื่อตัวอย่างนี้) สิ่งนี้จะทำให้ $myPerson เป็นอ็อบเจ็กต์ David:
<?php
$myPerson = บุคคล::GetPerson($ชื่อ);
$myPerson->เพิ่มคำติชม($messageArray);
?>
เกิดข้อผิดพลาดในการวิเคราะห์! ข้อความแสดงข้อผิดพลาดทั่วไปคือ ไม่มีวิธีการ ParseFeedback หรือมีข้อมูลบางอย่างที่คล้ายกัน มาพูดถึงการเชื่อมโยงล่าช้าใน PHP 5 กันดีกว่า! ต่อไป เราจะสรุปแนวคิดของการผูกล่าช้า
การผูกล่าช้าหมายความว่าการเรียกเมธอดไม่ได้ถูกผูกไว้กับวัตถุเป้าหมายจนกระทั่งวินาทีสุดท้าย ซึ่งหมายความว่าเมื่อมีการเรียกใช้เมธอดขณะรันไทม์ อ็อบเจ็กต์เหล่านั้นจะมีประเภทที่เป็นรูปธรรมอยู่แล้ว ในตัวอย่างข้างต้น คุณเรียกว่า David::AddFeedback() และเนื่องจาก $this ใน David::AddFeedback() อ้างอิงถึงอ็อบเจ็กต์ของ David คุณจึงสามารถสันนิษฐานตามหลักตรรกะได้ว่ามีเมธอด ParseFeedback() อยู่ - แต่จริงๆ แล้ว มันไม่ได้เป็นเช่นนั้น มีอยู่เนื่องจาก AddFeedback() ถูกกำหนดไว้ใน Person และ ParseFeedback() ถูกเรียกจากคลาส Person
น่าเสียดายที่ไม่มีวิธีง่ายๆ ในการกำจัดพฤติกรรมนี้ใน PHP 5 ซึ่งหมายความว่าคุณอาจไม่มีพลังเล็กน้อยเมื่อคุณต้องการสร้างลำดับชั้นของคลาส polymorphic ที่ยืดหยุ่น
ฉันต้องชี้ให้เห็นว่าฉันเลือก PHP 5 เป็นภาษานิพจน์สำหรับบทความนี้ เพียงเพราะ: ภาษานี้ไม่ได้ตระหนักถึงแนวคิดที่เป็นนามธรรมที่สมบูรณ์แบบ! สิ่งนี้สามารถเข้าใจได้เนื่องจาก PHP 5 ยังอยู่ในเวอร์ชันเบต้า นอกจากนี้ เมื่อเพิ่มคลาสนามธรรมและอินเทอร์เฟซให้กับภาษาแล้ว การผูกล่าช้าก็ควรถูกนำมาใช้ด้วย
5. สรุป
ณ จุดนี้ คุณควรมีความเข้าใจพื้นฐานว่า polymorphism คืออะไร และเหตุใด PHP 5 จึงไม่สมบูรณ์แบบในการบรรลุถึง polymorphism โดยทั่วไป คุณควรรู้วิธีใช้โมเดลวัตถุโพลีมอร์ฟิกเพื่อสรุปพฤติกรรมที่มีเงื่อนไข แน่นอนว่านี่เป็นการเพิ่มความยืดหยุ่นให้กับออบเจ็กต์ของคุณ และทำให้โค้ดใช้งานน้อยลง นอกจากนี้ คุณยังเพิ่มความชัดเจนของโค้ดของคุณด้วยการสรุปพฤติกรรมที่ตรงตามเงื่อนไขบางประการ (ขึ้นอยู่กับสถานะของออบเจ็กต์)