ปัญหาที่พบเจอบ่อยในการเขียนโปรแกรมคือ เมื่อโปรแกรมมีความซับซ้อนและจำนวนโค้ดที่มากขึ้นทำให้ยากจะดูแล คนในทีมก็ยากจะทำงานร่วมกันได้เพราะแต่ละคนมีรูปแบบการเขียนโค้ดที่ไม่เหมือนกัน ในกรณีที่โปรแกรมต้องการพัฒนาให้มีฟังก์ชันในการทำงานที่มากกว่าเดิมก็ทำได้ยาก เพราะตัวโค้ดเองถูกพัฒนาโดยไม่มีรูปแบบ
Design patterns คือรูปแบบการเขียนโปรแกรมที่ถูกพัฒนาขึ้นเพื่อแก้ปัญหาโค้ดที่ดูซับซ้อนให้ดูได้ง่ายขึ้น ทำให้ผู้พัฒนาและทีมสามารถเข้าใจสิ่งที่โปรแกรมต้องทำได้ง่ายขึ้นและสามารถเพิ่มฟังก์ชันใหม่ๆเข้าไปในระบบได้ง่ายขึ้น โดยรูปแบบต่างๆถูกคิดค้นมาเพื่อใช้ในงานที่ต่างกัน
Design Patterns นั้นสามารถแบ่งเป็นกลุ่มใหญ่ๆตามรูปแบบการใช้งานได้ทั้งหมด 3 กลุ่มดังนี้
- creational
- structural
- behavioral
Creational เป็นรูปแบบการเขียนที่ทำให้ตัวอ็อบเจกต์สามารถสร้างอ๊อบเจกต์อื่นๆขึ้นมาระหว่างการทำงานได้
Structural เป็นรูปแบบการเขียนที่ทำให้แต่ละอ็อบเจกต์ที่มีอยู่แล้วให้สามารถทำงานร่วมกันได้
Behavioral เป็นรูปแบบการเขียนที่ควบคุมการส่งข้อมูลระหว่างแต่ล่ะอ๊อบเจกต์
ตัวอย่างการใช้งาน ทุกครั้งที่มีการพูดถึง design patterns จำเป็นอย่างยิ่งที่จะต้องมีโค้ดประกอบ ซึ่งหากจะให้ลงลึกในทุกหัวข้ออาจทำให้บทความนี้มีความยาวมากเกินไป จึงขอยกตัวอย่างการทำใช้งาน design patterns ในกลุ่ม cretional ที่มีการใช้งานบ่อย
Creational
จากรูปการเขียนโค้ดในรูปแบบในกลุ่มของ Creational นั้นจะเป็นการทำงานโดยผ่าน Creator โดยหน้าที่หลักๆคือ หลังจากที่มี Request เข้ามาจะทำการเรียกอ็อบเจกต์ที่จำเป็นต้องใช้งานแล้วส่งค่ากลับไปยัง Request จะสังเกตได้ว่าตัว Request นั้นไม่จำเป็นจะต้องรู้เลยว่าอ๊อฟเจกต์ทำงานอย่างไรแค่เรียกสิ่งที่อยากได้ก็พอ และตัว Creator เองก็ไม่จำเป็นต้องรู้ว่าระบบทำงานอย่างไรแค่เรียกอ๊อบเจกต์ให้ทำงานแล้วส่งกลับไปให้ Request ก็พอ การทำงานส่วนใหญ่จะอยู่ที่ Abstracted Object โดยเราจะแบ่งงานที่มีความซับซ้อนออกเป็นกลุ่มที่ทำงานในลักษณะเดียวกัน จากนั้นให้ส่วนของ Creator คอยควบคุมการการสร้างอ็อบเจกต์ใหม่ให้ตรงกับความต้องการของ Request ก็พอ
Creational สามารถแยกย่อยได้ออกเป็นอีกหลายรูปแบบ โดยแต่ละรูปแบบจะมีลักษณะการทำงานที่เหมือนกันคือมี Creator คอยสร้างอ็อบเจกต์ขึ้นมา
ตัวอย่าง Design Patterns ที่อยู่ในกลุ่ม Creational
- Factory Method
- Prototype
- Adapter
- Decorator
Factory Method
Factory Method เป็น Design Patterns หนึ่งที่อยู่ในกลุ่มของ Creational ซึ่งแน่นอนว่าการทำงานตัองอยู่ในรูปแบบมี Creator คอยสร้างอ๊อบเจกต์อื่นขึ้นมาอย่างแน่นอน
ตัวออย่างการใช้งาน Factory Method Design Pattern
ตัวอย่างนี้สมมุติให้เป็นการพัฒนาโปรแกรมสำหรับชำระเงินออนไลน์ โดยจะมีทั้งหมด 2 วิธีคือ
1.ผ่านทางระบบ Paypal
2.ผ่านทางระบบ Credit Card
โดยวิธีการชำระเงิน 2 ระบบนี้มีความแตกต่างกันในการส่งข้อมูลไปยังเซิร์ฟเวอร์ที่ใช้ในการชำระเงิน และรับค่าที่ถูกส่งมาจากเซิร์ฟเวอร์ของระบบชำระเงินมายังระบบซึ่งขั้นตอนต่างๆของการชำระเงินของทั้ง 2 วิธีนั้นไม่มีทางเหมือนกันอย่างแน่นอน หากไม่มีการใช้ design patterns เข้ามาช่วยรับรองได้ว่าโค้ดจะต้องมีความยุ่งเหยิงมาก เพราะต้องรองรับการทำงานของระบบ 2 วิธีที่ไม่เหมือนกัน นอกจากนี้หากมีระบบใหม่เพิ่มขึ้นมาเช่น มีการเปลี่ยนธนาคารที่ใช้ในการชำระเงิน การแก้ไขจะมีความยุ่งยากมาก
ในกรณีนี้จึงแยกการทำงานของทั้ง 2 ระบบออกเป็น 2 คลาส คือ Paypal , Creditcard โดย Extended มาจากคลาส Payment หากต้องการใช้งานคลาสทั้ง 2 ก็สามารถเรียกใช้งานผ่านทางคลาส PaymentFactory ดังภาพด้านล่าง
ตัวอย่างโค้ด
Payment.php
1 2 3 4 5 6 7 8 |
interface Payment { //เมธอดสำหรับเตรียมข้อมูลเพื่อส่งไปเซิร์ฟเวอร์ของระบบชำระเงิน public function createTransaction(); //เมธอดสำหรับรับข้อมูลที่ส่งกลับมาจากเซิร์ฟเวอร์ของระบบชำระเงิน public function callbackTransaction(); } |
ไฟล์นี้ใช้สำหรับเป็นแม่แบบให้กับไฟล์ paypal.php , creditcard.php ความสำคัญที่จำเป็นต้องใช้ interface เพื่อให้คลาสทั้ง 2 มีเมธอดที่เหมือนกันเพื่อให้ paymentfactory เรียกใช้ได้ถูกต้อง และเผื่อไว้ในกรณีที่มีระบบการชำระเงินแบบใหม่จะได้ดูตัวอย่างการเขียนจาก interface คลาสและสามารถเข้าใจการทำงานของระบบได้เร็วขึ้น
PayPal.php
1 2 3 4 5 6 7 8 9 10 11 12 |
class PayPal implements Payment { public function createTransaction() { //การเตรียมค่าสำหรับระบบชำระเงินผ่านระบบ PayPal }; public function callbackTransaction() { //หลังจากรับค่าจากเซิร์ฟเวอร์ของระบบ PayPal ต้องการให้ทำอะไรต่อไป }; } |
CreditCard.php
1 2 3 4 5 6 7 8 9 10 11 12 |
class CreditCard implements Payment { public function createTransaction() { //การเตรียมค่าสำหรับระบบชำระเงินผ่านระบบ Credit Card }; public function callbackTransaction() { //หลังจากรับค่าจากเซิร์ฟเวอร์ของระบบ Credit Card ต้องการให้ทำอะไรต่อไป }; } |
จะเห็นได้ว่าทั้ง 2 ไฟล์นั้นสามารถอ่านเข้าใจได้ง่ายขึ้น ไม่มีความซับซ้อนเหลือคลาสใดทำอะไรก็จบในคลาสนั้นได้ ถ้าหากต้องการเพิ่มระบบชำระเงินก็สามารถเพิ่มคลาสใหม่เข้ามาในระบบโดยอ้างอิงจาก Payment คลาสซึ่งเป็น Interface ได้ทันที
PaymentFactory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PaymentFactory { public static function paymentGateway($type) { $targetClass = ucfirst($type); if (class_exists($targetClass) && is_subclass_of($targetClass, $baseClass)) { return new $targetClass; } else { throw new Exception("The Payment type '$type' is not recognized."); } } } |
คลาส PaymentFactory คือหัวใจของการทำงานโดยทำหน้าที่เป็น Creator สำหรับสร้างอ็อบเจกต์ใหม่ขึ้นมาและส่งกลับไปยัง Request
ยังมีข้อสงสัยเรื่อง Factory Method แนะนำให้อ่านเพิ่มเติมที่นี่ได้ http://www.oodesign.com/factory-pattern.html
สรุป
จากประสพการณ์ในการพัฒนา เมื่อการ design patterns มาใช้พบว่าสามารถทำให้การทำงานรวดเร็วขึ้น เพราะระหว่างการพัฒนาไม่จำเป็นต้องวางคิดรูปแบบการเขียนโค้ดเอง แต่เลือกใช้จากรูปแบบที่มีคนอื่นคิดไว้แล้ว เมื่อจะให้คนอื่นทำงานต่อจากส่วนที่เราทำไว้ก็แค่บอกว่าเราได้เลือกใช้ design patterns แบบใดเอาไว้ก็สามารถต่องานกันได้โดยไม่จำเป็นต้องอธิบายมาก และตัวเราเองเมื่อกลับมาแก้ไขโค้ดที่ตัวเองได้เขียนไว้ก็สามารถทำได้ง่ายด้วย
Design Patterns นั้นช่วยให้เราสามารถทำงานได้เร็วขึ้นแต่ไม่ได้ช่วยให้โปรแกรมของเรามีประสิทธิ์ภาพมากขึ้น ดังนั้นเราควรศึกษารูปแบบเอาไว้ให้มากๆเพราะให้เราได้เลือกใช้ได้ตรงจุดประสงค์ มีคำกล่าวที่ว่า “หากค้อนเป็นเครื่องมืออย่างเดียวที่เรามีอยู่ จงมองทุกงานให้เป็นตะปู” สิ่งนี้ใช้ไม่ได้กับการใช้งาน design patterns เพราะหากเลือกใช้งานผิดแทนที่จะช่วยให้เราทำงานได้เร็วขึ้นกลับจะทำให้ทุกอย่างแย่ลง
หนังสือแนะนำสำหรับผู้อยากศึกษาเพิ่มเติม
Learning PHP Design Patterns