รูปแบบการออกแบบมีไว้สำหรับสถาปนิก Java เท่านั้น - อย่างน้อยนั่นคือสิ่งที่คุณอาจคิดมาตลอด ที่จริงแล้ว รูปแบบการออกแบบมีประโยชน์สำหรับทุกคน หากเครื่องมือเหล่านี้ไม่ใช่ของสงวน "นักบินอวกาศทางสถาปัตยกรรม" แล้วเครื่องมือเหล่านี้คืออะไร? เหตุใดจึงมีประโยชน์ในแอปพลิเคชัน PHP บทความนี้จะอธิบายปัญหาเหล่านี้
หนังสือ Design Patterns ได้แนะนำรูปแบบการออกแบบให้กับชุมชนซอฟต์แวร์ ผู้เขียนหนังสือเล่มนี้ ได้แก่ Erich Gamma, Richard Helm, Ralph Johnson และ John Vlissides Design (ที่รู้จักกันทั่วไปในชื่อ "Gang of Four") แนวคิดหลักเบื้องหลังรูปแบบการออกแบบที่นำเสนอนั้นเรียบง่ายมาก หลังจากฝึกฝนการพัฒนาซอฟต์แวร์มาหลายปี Gamma และคนอื่นๆ ได้ค้นพบรูปแบบบางอย่างที่มีการออกแบบคงที่ เหมือนกับที่สถาปนิกออกแบบบ้านและอาคาร การพัฒนาเทมเพลตสำหรับตำแหน่งห้องน้ำที่ควรอยู่ หรือวิธีสร้างห้องครัว การใช้เทมเพลตหรือรูปแบบการออกแบบเหล่านี้หมายถึงการออกแบบอาคารที่ดีขึ้นเร็วขึ้น แนวคิดเดียวกันนี้ใช้กับซอฟต์แวร์
รูปแบบการออกแบบไม่เพียงแต่แสดงถึงวิธีที่เป็นประโยชน์ในการพัฒนาซอฟต์แวร์ที่มีประสิทธิภาพเร็วขึ้นเท่านั้น แต่ยังเป็นวิธีในการสรุปแนวคิดขนาดใหญ่ในแง่ที่เป็นมิตรอีกด้วย ตัวอย่างเช่น คุณอาจบอกว่าคุณกำลังเขียนระบบการส่งข้อความที่ให้การเชื่อมต่อแบบหลวมๆ หรือคุณอาจบอกว่าคุณกำลังเขียนรูปแบบชื่อ Observer
การแสดงคุณค่าของรูปแบบด้วยตัวอย่างเล็กๆ น้อยๆ เป็นเรื่องยากมาก สิ่งนี้มักจะรู้สึกเหมือนต้องใช้กำลังมากเกินไป เนื่องจากรูปแบบใช้งานได้จริงในฐานโค้ดขนาดใหญ่ บทความนี้ไม่ได้สาธิตแอปพลิเคชันขนาดใหญ่ ดังนั้นคุณต้องคิดถึงวิธีใช้หลักการของตัวอย่างในแอปพลิเคชันขนาดใหญ่ของคุณเอง ไม่ใช่โค้ดที่แสดงในบทความนี้ นี่ไม่ได้เป็นการบอกว่าคุณไม่ควรใช้รูปแบบในแอปพลิเคชันขนาดเล็ก แอปพลิเคชันที่ดีจำนวนมากเริ่มต้นจากแอปพลิเคชันขนาดเล็กและก้าวหน้าไปสู่แอปพลิเคชันขนาดใหญ่ ดังนั้นจึงไม่มีเหตุผลที่จะไม่ต่อยอดแนวทางการเขียนโค้ดที่มั่นคงประเภทนี้ ตอนนี้คุณเข้าใจรูปแบบการออกแบบแล้วและเหตุใดจึงมีประโยชน์ เรามาดูรูปแบบที่ใช้กันทั่วไปทั้ง 5 รูปแบบใน PHP V5 กันดีกว่า
แบบโรงงาน
เดิมทีมีอยู่ในหนังสือ Design Patterns รูปแบบการออกแบบหลายรูปแบบสนับสนุนการใช้ข้อต่อแบบหลวม เพื่อให้เข้าใจแนวคิดนี้ เป็นการดีที่สุดที่จะพูดถึงการเดินทางที่ยากลำบากที่นักพัฒนาจำนวนมากต้องเผชิญในการทำงานกับระบบขนาดใหญ่ เมื่อคุณเปลี่ยนโค้ดชิ้นเดียว ปัญหาอาจเกิดขึ้นได้ และการหยุดต่อเนื่องสามารถเกิดขึ้นได้ในส่วนอื่นๆ ของระบบ ซึ่งเป็นส่วนที่คุณเคยคิดว่าไม่เกี่ยวข้องกันโดยสิ้นเชิง
ปัญหาคือการมีเพศสัมพันธ์ที่แน่น ฟังก์ชันและคลาสในส่วนหนึ่งของระบบจะขึ้นอยู่กับพฤติกรรมและโครงสร้างของฟังก์ชันและคลาสในส่วนอื่นๆ ของระบบอย่างมาก คุณต้องการชุดรูปแบบที่ช่วยให้คลาสเหล่านี้สื่อสารกัน แต่คุณไม่ต้องการผูกมันเข้าด้วยกันอย่างแน่นหนาเพื่อหลีกเลี่ยงการประสานกัน ในระบบขนาดใหญ่ โค้ดจำนวนมากขึ้นอยู่กับคลาสคีย์บางคลาส ปัญหาอาจเกิดขึ้นเมื่อจำเป็นต้องเปลี่ยนคลาสเหล่านี้ ตัวอย่างเช่น สมมติว่าคุณมีคลาส User ที่อ่านจากไฟล์ คุณต้องการเปลี่ยนเป็นคลาสอื่นที่อ่านจากฐานข้อมูล อย่างไรก็ตาม รหัสทั้งหมดของคุณอ้างอิงถึงคลาสดั้งเดิมที่อ่านจากไฟล์ ในเวลานี้การใช้โหมดโรงงานจะสะดวกมาก
รูปแบบโรงงานเป็นคลาสที่มีวิธีการบางอย่างที่สร้างวัตถุสำหรับคุณ คุณสามารถใช้คลาสโรงงานเพื่อสร้างวัตถุโดยไม่ต้องใช้สิ่งใหม่โดยตรง ด้วยวิธีนี้ หากคุณต้องการเปลี่ยนประเภทของออบเจ็กต์ที่สร้างขึ้น คุณจะต้องเปลี่ยนโรงงานเท่านั้น รหัสทั้งหมดที่ใช้โรงงานนี้จะถูกเปลี่ยนโดยอัตโนมัติ
รายการที่ 1 แสดงตัวอย่างคลาสโรงงาน ฝั่งเซิร์ฟเวอร์ของสมการประกอบด้วยสองส่วน: ฐานข้อมูลและชุดของเพจ PHP ที่ให้คุณเพิ่มคำติชม ขอรายการคำติชม และรับบทความที่เกี่ยวข้องกับคำติชมเฉพาะ
รายการ 1. Factory1.php
<?php อินเทอร์เฟซ IUser - ฟังก์ชัน getName(); -
ผู้ใช้ระดับดำเนินการ IUser - ฟังก์ชั่นสาธารณะ __ สร้าง ( $id ) { }
ฟังก์ชั่นสาธารณะ getName() - กลับ "แจ็ค"; - -
คลาส UserFactory - สร้างฟังก์ชันคงที่สาธารณะ ( $id ) - ส่งคืนผู้ใช้ใหม่( $id ); - -
$uo = UserFactory::สร้าง( 1 ); echo( $uo->getName()"n" ); ? |
อินเทอร์เฟซ IUser กำหนดการกระทำที่วัตถุผู้ใช้ควรทำ การใช้งาน IUser เรียกว่า User และคลาสโรงงาน UserFactory จะสร้างอ็อบเจ็กต์ IUser ความสัมพันธ์นี้สามารถแสดงได้ด้วย UML ในรูปที่ 1
รูปที่ 1 คลาสโรงงานและอินเทอร์เฟซ IUser และคลาสผู้ใช้ที่เกี่ยวข้อง |
หากคุณเรียกใช้โค้ดนี้บนบรรทัดคำสั่งโดยใช้ตัวแปล php คุณจะได้รับผลลัพธ์ต่อไปนี้:
รหัสทดสอบจะร้องขอออบเจ็กต์ User จากโรงงานและส่งออกผลลัพธ์ของเมธอด getName
มีรูปแบบของโรงงานที่แตกต่างกันซึ่งใช้วิธีการของโรงงาน วิธีการคงที่สาธารณะเหล่านี้ในคลาสสร้างวัตถุประเภทนั้น วิธีการนี้มีประโยชน์หากจำเป็นต้องสร้างออบเจ็กต์ประเภทนี้ ตัวอย่างเช่น สมมติว่าคุณจำเป็นต้องสร้างออบเจ็กต์แล้วตั้งค่าคุณสมบัติจำนวนหนึ่ง รูปแบบโรงงานเวอร์ชันนี้สรุปกระบวนการไว้ในที่เดียว ดังนั้นคุณจึงไม่ต้องคัดลอกโค้ดเริ่มต้นที่ซับซ้อนแล้ววางลงบนฐานโค้ดทั้งหมด รายการที่ 2 แสดงตัวอย่างการใช้วิธีแบบโรงงาน
รายการ 2. Factory2.php
<?php อินเทอร์เฟซ IUser - ฟังก์ชัน getName(); -
ผู้ใช้ระดับดำเนินการ IUser - โหลดฟังก์ชันคงที่สาธารณะ ( $id ) - ส่งคืนผู้ใช้ใหม่( $id ); -
ฟังก์ชั่นคงที่สาธารณะสร้าง () - ส่งคืนผู้ใช้ใหม่ (null); -
ฟังก์ชั่นสาธารณะ __ สร้าง ( $id ) { }
ฟังก์ชั่นสาธารณะ getName() - กลับ "แจ็ค"; - -
$uo = ผู้ใช้::โหลด( 1 ); echo( $uo->getName()"n" ); ? |
รหัสนี้ง่ายกว่ามาก มีอินเทอร์เฟซเดียว IUser และคลาสผู้ใช้ที่ใช้อินเทอร์เฟซนี้ คลาส User มีสองวิธีคงที่สำหรับการสร้างวัตถุ ความสัมพันธ์นี้สามารถแสดงได้ด้วย UML ในรูปที่ 2
รูปที่ 2 ส่วนต่อประสาน IUser และคลาสผู้ใช้ด้วยวิธีจากโรงงาน |
การรันสคริปต์บนบรรทัดคำสั่งจะให้ผลลัพธ์เหมือนกับรายการ 1 ดังนี้:
ตามที่กล่าวไว้ข้างต้น บางครั้งโหมดดังกล่าวอาจดูเหมือนใช้งานมากเกินไปในสภาพแวดล้อมขนาดเล็ก อย่างไรก็ตาม ทางที่ดีที่สุดคือเรียนรู้รูปแบบการเขียนโค้ดที่แข็งแกร่งซึ่งคุณสามารถนำไปใช้กับโปรเจ็กต์ทุกขนาดได้
โหมดองค์ประกอบเดียว
ทรัพยากรของแอปพลิเคชันบางอย่างเป็นแบบเอกสิทธิ์เฉพาะบุคคลเนื่องจากมีทรัพยากรประเภทนี้เพียงแหล่งเดียวเท่านั้น ตัวอย่างเช่น การเชื่อมต่อกับฐานข้อมูลผ่านตัวจัดการฐานข้อมูลเป็นแบบเอกสิทธิ์เฉพาะบุคคล คุณต้องการแชร์ตัวจัดการฐานข้อมูลทั่วทั้งแอปพลิเคชันของคุณ เนื่องจากเป็นค่าใช้จ่ายเมื่อเปิดหรือปิดการเชื่อมต่อ ยิ่งกว่านั้นในระหว่างกระบวนการดึงข้อมูลเพจเดียว
โหมดองค์ประกอบเดี่ยวเป็นไปตามข้อกำหนดนี้ หากแอปพลิเคชันมีวัตถุเพียงชิ้นเดียวในแต่ละครั้ง แสดงว่าวัตถุนี้จะเป็นซิงเกิลตัน รหัสในรายการ 3 แสดงการเชื่อมต่อฐานข้อมูลองค์ประกอบเดียวใน PHP V5
รายการ 3. Singleton.php
<?php need_once("DB.php");
การเชื่อมต่อฐานข้อมูลคลาส - ฟังก์ชั่นคงที่สาธารณะรับ () - คงที่ $db = null; ถ้า ( $db == null ) $db = การเชื่อมต่อฐานข้อมูลใหม่(); ส่งคืน $db; -
ส่วนตัว $_handle = null; ฟังก์ชั่นส่วนตัว __ สร้าง () - $dsn = 'mysql://root:password@localhost/photos'; $this->_handle =& DB::Connect( $dsn, array() ); -
หมายเลขอ้างอิงฟังก์ชั่นสาธารณะ () - กลับ $this->_handle; - -
พิมพ์( "Handle = ".DatabaseConnection::get()->handle()."n" ); พิมพ์( "Handle = ".DatabaseConnection::get()->handle()."n" ); ? |
รหัสนี้แสดงคลาสเดียวชื่อ DatabaseConnection คุณไม่สามารถสร้างการเชื่อมต่อฐานข้อมูลของคุณเองได้เนื่องจากตัวสร้างเป็นแบบส่วนตัว แต่เมื่อใช้วิธีรับแบบคงที่ คุณสามารถรับและรับออบเจ็กต์ DatabaseConnection ได้เพียงรายการเดียวเท่านั้น UML สำหรับโค้ดนี้แสดงในรูปที่ 3
รูปที่ 3 การเชื่อมต่อฐานข้อมูลองค์ประกอบเดียว |
ข้อพิสูจน์ที่ดีที่สุดคือตัวจัดการฐานข้อมูลที่ส่งคืนโดยวิธีจัดการจะเหมือนกันระหว่างการโทรทั้งสองครั้ง คุณสามารถเรียกใช้โค้ดในบรรทัดคำสั่งเพื่อสังเกตสิ่งนี้
% php singleton.php หมายเลขอ้างอิง = รหัสวัตถุ #3 หมายเลขอ้างอิง = รหัสวัตถุ #3 - |
หมายเลขอ้างอิงทั้งสองที่ส่งคืนเป็นวัตถุเดียวกัน หากคุณใช้องค์ประกอบเดียวในการเชื่อมต่อฐานข้อมูลทั่วทั้งแอปพลิเคชันของคุณ คุณสามารถใช้หมายเลขอ้างอิงเดิมซ้ำได้ทุกที่
คุณสามารถใช้ตัวแปรส่วนกลางเพื่อจัดเก็บหมายเลขอ้างอิงฐานข้อมูลได้ อย่างไรก็ตาม วิธีการนี้เหมาะสำหรับแอปพลิเคชันขนาดเล็กเท่านั้น ในแอปพลิเคชันขนาดใหญ่ ให้หลีกเลี่ยงการใช้ตัวแปรส่วนกลาง และใช้อ็อบเจ็กต์และวิธีการในการเข้าถึงทรัพยากร รูปแบบผู้สังเกตการณ์
รูปแบบ Observer เป็นอีกวิธีหนึ่งในการหลีกเลี่ยงการเชื่อมต่อที่แน่นแฟ้นระหว่างส่วนประกอบต่างๆ รูปแบบนั้นง่ายมาก: วัตถุทำให้สังเกตตัวเองได้โดยการเพิ่มวิธีการที่อนุญาตให้วัตถุอื่นซึ่งก็คือผู้สังเกตการณ์ลงทะเบียนตัวเองได้ เมื่อวัตถุที่สังเกตได้เปลี่ยนแปลง มันจะส่งข้อความไปยังผู้สังเกตการณ์ที่ลงทะเบียนไว้ ผู้สังเกตการณ์เหล่านี้ใช้ข้อมูลนี้เพื่อดำเนินการโดยไม่ขึ้นกับวัตถุที่สังเกตได้ ผลลัพธ์ก็คือวัตถุสามารถพูดคุยกันได้โดยไม่จำเป็นต้องเข้าใจว่าเหตุใด ตัวอย่างง่ายๆ คือ รายชื่อผู้ใช้ในระบบ รหัสในรายการ 4 แสดงรายการผู้ใช้ และเมื่อมีการเพิ่มผู้ใช้ ระบบจะส่งข้อความ รายการนี้สามารถตรวจสอบได้ผ่านทางผู้สังเกตการณ์บันทึกซึ่งจะส่งข้อความเมื่อมีการเพิ่มผู้ใช้
รายการ 4. Observer.php
<?php อินเทอร์เฟซ IObserver - ฟังก์ชั่น onChanged( $sender, $args ); -
อินเทอร์เฟซ IO ที่สามารถสังเกตได้ - ฟังก์ชั่น addObserver( $observer ); -
คลาส UserList ใช้ IObservable - ส่วนตัว $_observers = array();
ฟังก์ชั่นสาธารณะ addCustomer( $name ) - foreach( $this->_observers เป็น $obs ) $obs->onChanged( $นี่, $ชื่อ ); -
ฟังก์ชั่นสาธารณะ addObserver( $ ผู้สังเกตการณ์ ) - $this->_observers []= $observer; - -
คลาส UserListLogger ใช้งาน IObserver - ฟังก์ชั่นสาธารณะ onChanged( $sender, $args ) - echo( "'$args' ถูกเพิ่มเข้าไปในรายชื่อผู้ใช้n" ); - -
$ul = รายชื่อผู้ใช้ใหม่(); $ul->addObserver( UserListLogger ใหม่() ); $ul->addCustomer( "แจ็ค" ); ? |
รหัสนี้กำหนดสี่องค์ประกอบ: สองอินเทอร์เฟซและสองคลาส อินเทอร์เฟซ IObservable กำหนดวัตถุที่สามารถสังเกตได้ และ UserList ใช้อินเทอร์เฟซนี้เพื่อลงทะเบียนตัวเองว่าสามารถสังเกตได้ รายการ IObserver กำหนดวิธีการเป็นผู้สังเกตการณ์ UserListLogger ใช้อินเทอร์เฟซ IObserver องค์ประกอบเหล่านี้แสดงใน UML ในรูปที่ 4
รูปที่ 4 รายชื่อผู้ใช้ที่สังเกตได้และตัวบันทึกเหตุการณ์รายชื่อผู้ใช้ |
หากคุณเรียกใช้จากบรรทัดคำสั่ง คุณจะเห็นผลลัพธ์ต่อไปนี้:
% php ผู้สังเกตการณ์.php เพิ่ม 'แจ็ค' ลงในรายชื่อผู้ใช้แล้ว - |
รหัสทดสอบจะสร้าง UserList และเพิ่ม UserListLogger ผู้สังเกตการณ์ลงไป จากนั้นเพิ่มผู้บริโภคและแจ้ง UserListLogger เกี่ยวกับการเปลี่ยนแปลงนี้
สิ่งสำคัญคือต้องตระหนักว่า UserList ไม่รู้ว่าคนตัดไม้จะทำอะไร อาจมีผู้ฟังตั้งแต่หนึ่งคนขึ้นไปที่ดำเนินการอื่น ตัวอย่างเช่น คุณอาจมีผู้สังเกตการณ์ที่ส่งข้อความถึงผู้ใช้ใหม่เพื่อต้อนรับพวกเขาเข้าสู่ระบบ คุณค่าของแนวทางนี้คือ UserList จะละเว้นออบเจ็กต์ทั้งหมดที่ขึ้นอยู่กับรายการนั้น และมุ่งเน้นที่การรักษารายชื่อผู้ใช้และการส่งข้อความเป็นหลักเมื่อรายการเปลี่ยนแปลง
รูปแบบนี้ไม่จำกัดเฉพาะวัตถุในหน่วยความจำ เป็นพื้นฐานสำหรับระบบสืบค้นข้อความที่ขับเคลื่อนด้วยฐานข้อมูลที่ใช้ในแอปพลิเคชันขนาดใหญ่ สายโซ่ของโหมดคำสั่ง
รูปแบบสายการบังคับบัญชาจะขึ้นอยู่กับหัวข้อที่เชื่อมโยงอย่างหลวมๆ การส่งข้อความ คำสั่ง คำร้องขอ หรือสิ่งอื่นใดผ่านชุดตัวจัดการ ตัวจัดการแต่ละรายจะตัดสินใจเองว่าสามารถจัดการคำขอได้หรือไม่ หากทำได้ คำขอจะได้รับการประมวลผลและกระบวนการจะหยุดลง คุณสามารถเพิ่มหรือลบตัวจัดการออกจากระบบได้โดยไม่ส่งผลกระทบต่อตัวจัดการอื่นๆ รายการที่ 5 แสดงตัวอย่างรูปแบบนี้
รายการ 5. Chain.php
<?php อินเทอร์เฟซ ICommand - ฟังก์ชั่น onCommand( $name, $args ); -
คลาส CommandChain - ส่วนตัว $_commands = array();
ฟังก์ชั่นสาธารณะ addCommand( $cmd ) - $this->_commands []= $cmd; -
ฟังก์ชั่นสาธารณะ runCommand( $name, $args ) - foreach( $this->_commands เป็น $cmd ) - ถ้า ( $cmd->onCommand( $name, $args ) ) กลับ; - - -
คลาส UserCommand ใช้ ICommand - ฟังก์ชั่นสาธารณะ onCommand( $name, $args ) - ถ้า ( $name != 'addUser' ) กลับเท็จ; echo( "การจัดการคำสั่งผู้ใช้ 'addUser'n" ); กลับเป็นจริง; - -
คลาส MailCommand ใช้ ICommand - ฟังก์ชั่นสาธารณะ onCommand( $name, $args ) - ถ้า ( $name != 'mail' ) กลับเท็จ; echo( "การจัดการ MailCommand 'mail'n" ); กลับเป็นจริง; - -
$cc = CommandChain ใหม่(); $cc->addCommand( คำสั่งผู้ใช้ใหม่() ); $cc->addCommand( คำสั่ง Mail ใหม่() ); $cc->runCommand( 'addUser', null ); $cc->runCommand( 'เมล', null ); ? |
รหัสนี้กำหนดคลาส CommandChain ที่เก็บรักษารายการของอ็อบเจ็กต์ ICommand ทั้งสองคลาสสามารถใช้อินเทอร์เฟซ ICommand ได้ - คลาสหนึ่งตอบสนองต่อการร้องขอเมล และอีกคลาสหนึ่งที่ตอบสนองต่อการเพิ่มผู้ใช้ รูปที่ 5 แสดง UML
รูปที่ 5 สายคำสั่งและคำสั่งที่เกี่ยวข้อง |
หากคุณเรียกใช้สคริปต์ที่มีโค้ดทดสอบ คุณจะได้รับผลลัพธ์ต่อไปนี้:
% php chain.php คำสั่งผู้ใช้จัดการ 'addUser' MailCommand การจัดการ 'เมล' - |
ขั้นแรกโค้ดจะสร้างอ็อบเจ็กต์ CommandChain และเพิ่มสองอินสแตนซ์ของอ็อบเจ็กต์คำสั่งเข้าไป จากนั้นรันสองคำสั่งเพื่อดูว่าใครตอบสนองต่อคำสั่ง หากชื่อของคำสั่งตรงกับ UserCommand หรือ MailCommand โค้ดจะล้มเหลวและไม่มีการดำเนินการใดๆ เกิดขึ้น รูปแบบสายการบังคับบัญชามีคุณค่าเมื่อสร้างสถาปัตยกรรมที่ปรับขนาดได้สำหรับจัดการคำขอ และปัญหาต่างๆ มากมายสามารถแก้ไขได้โดยใช้รูปแบบดังกล่าว รูปแบบกลยุทธ์
รูปแบบการออกแบบสุดท้ายที่เรากล่าวถึงคือรูปแบบกลยุทธ์ ในรูปแบบนี้ อัลกอริธึมจะถูกแยกออกจากคลาสที่ซับซ้อนและสามารถแทนที่ได้อย่างง่ายดาย ตัวอย่างเช่น หากคุณต้องการเปลี่ยนวิธีการจัดอันดับหน้าเว็บในเครื่องมือค้นหา โหมดกลยุทธ์ถือเป็นตัวเลือกที่ดี ลองนึกถึงส่วนต่างๆ ของเครื่องมือค้นหา เช่น ส่วนต่างๆ ที่สำรวจหน้าต่างๆ ส่วนส่วนที่จัดอันดับแต่ละหน้า และส่วนอื่นๆ ที่จัดเรียงผลลัพธ์ตามการจัดอันดับ ในตัวอย่างที่ซับซ้อน ชิ้นส่วนเหล่านี้ทั้งหมดอยู่ในคลาสเดียวกัน ด้วยการใช้รูปแบบกลยุทธ์ คุณสามารถใส่ส่วนการจัดเรียงลงในคลาสอื่นเพื่อเปลี่ยนวิธีการจัดเรียงหน้าโดยไม่ส่งผลกระทบต่อโค้ดที่เหลือของเครื่องมือค้นหา
ตามตัวอย่างที่ง่ายกว่า รายการ 6 จะแสดงคลาสรายการผู้ใช้ที่ให้วิธีการค้นหาชุดผู้ใช้ตามชุดนโยบาย Plug-and-Play
รายการ 6. Strategy.php
<?php อินเทอร์เฟซ ISStrategy - ฟังก์ชั่นตัวกรอง( $บันทึก ); -
คลาส FindAfterStrategy ใช้ IStrategy - ส่วนตัว $_name;
ฟังก์ชั่นสาธารณะ __construct( $name ) - $นี่->_ชื่อ = $ชื่อ; -
ตัวกรองฟังก์ชั่นสาธารณะ ($ บันทึก) - return strcmp( $this->_name, $record ) <= 0; - -
คลาส RandomStrategy ใช้ IStrategy - ตัวกรองฟังก์ชั่นสาธารณะ ($ บันทึก) - ส่งคืนแรนด์ (0, 1) > = 0.5; - -
รายชื่อผู้ใช้คลาส - ส่วนตัว $_list = array();
ฟังก์ชั่นสาธารณะ __construct( $names ) - ถ้า ( $names != null ) - foreach( $ชื่อเป็น $ชื่อ ) - $this->_list []= $ชื่อ; - - -
เพิ่มฟังก์ชันสาธารณะ( $name ) - $this->_list []= $ชื่อ; -
ค้นหาฟังก์ชั่นสาธารณะ( $filter ) - $recs = อาร์เรย์(); foreach( $this->_list เป็น $user ) - ถ้า ( $filter->filter( $user ) ) $recs []= $ผู้ใช้; - ส่งคืน $recs; - -
$ul = รายชื่อผู้ใช้ใหม่( array( "Andy", "Jack", "Lori", "Megan" ) ); $f1 = $ul->find( FindAfterStrategy ใหม่( "J" ) ); print_r( $f1 );
$f2 = $ul->find( ใหม่ RandomStrategy() ); print_r( $f2 ); ? |
รูปที่ 6 รายชื่อผู้ใช้และนโยบายที่ใช้ในการเลือกผู้ใช้ |
คลาส UserList เป็น wrapper ล้อมรอบอาร์เรย์ของชื่อ ใช้วิธีการค้นหาซึ่งใช้หนึ่งในหลายกลยุทธ์เพื่อเลือกชุดย่อยของชื่อเหล่านี้ กลยุทธ์เหล่านี้ถูกกำหนดโดยอินเทอร์เฟซ IStrategy ซึ่งมีการใช้งานสองแบบ: แบบหนึ่งสุ่มเลือกผู้ใช้ และอีกแบบเลือกชื่อทั้งหมดหลังจากชื่อที่ระบุ เมื่อคุณรันโค้ดทดสอบ คุณจะได้รับผลลัพธ์ต่อไปนี้:
%php กลยุทธ์.php อาร์เรย์ - [0] => แจ็ค [1] =>ลอริ [2] =>เมแกน - อาร์เรย์ - [0] => แอนดี้ [1] =>เมแกน - - |
รหัสทดสอบจะเรียกใช้รายการผู้ใช้เดียวกันสำหรับทั้งสองกลยุทธ์และแสดงผลลัพธ์ ในกรณีแรก กลยุทธ์จะค้นหาชื่อใดๆ ที่ตามหลัง J ดังนั้นคุณจะได้รับ Jack, Lori และ Megan กลยุทธ์ที่สองเลือกชื่อโดยการสุ่ม ซึ่งให้ผลลัพธ์ที่แตกต่างกันในแต่ละครั้ง ในกรณีนี้ผลลัพธ์คือแอนดี้และเมแกน
รูปแบบกลยุทธ์เหมาะอย่างยิ่งสำหรับระบบการจัดการข้อมูลที่ซับซ้อนหรือระบบประมวลผลข้อมูลที่ต้องการความยืดหยุ่นในระดับสูงในการกรอง ค้นหา หรือประมวลผลข้อมูล
บทสรุป
บทความนี้จะแนะนำรูปแบบการออกแบบทั่วไปบางส่วนที่ใช้ในแอปพลิเคชัน PHP มีการแสดงรูปแบบการออกแบบเพิ่มเติมในหนังสือ Design Patterns อย่าปล่อยให้ความลึกลับของสถาปัตยกรรมทำให้คุณผิดหวัง Patterns เป็นแนวคิดที่ยอดเยี่ยมซึ่งใช้ได้กับทุกภาษาการเขียนโปรแกรมและทุกระดับทักษะ