1. แนวคิดของรูปแบบ Strategy
รูปแบบการทำงานเชิงพฤติกรรม (behavioral design pattern) หรือที่เรียกว่า "รูปแบบ Strategy" เป็นรูปแบบที่ช่วยให้เราสามารถเลือกใช้ขั้นตอนวิธีหรือพฤติกรรมต่าง ๆ ตามสถานการณ์ที่แตกต่างกันได้ โดยการห่อหุ้ม (encapsulate) ขั้นตอนวิธีต่าง ๆ ลงในคลาส Strategy แต่ละคลาสและอนุญาตให้คลาส Strategy เหล่านี้สามารถสลับกันได้ ด้วยการใช้รูปแบบ Strategy จะทำให้เราสามารถเปลี่ยนพฤติกรรมของอ็อบเจกต์ได้ในระหว่างรันไทม์โดยไม่ต้องแก้ไขโครงสร้างของอ็อบเจกต์โดยตรง
2. ลักษณะและข้อดีของรูปแบบ Strategy
รูปแบบ Strategy มีลักษณะและข้อดีดังนี้:
- คลาส Strategy สามารถเปลี่ยนแปลงได้อิสระโดยการเพิ่มคลาส Strategy ใหม่โดยไม่ส่งผลต่อโค้ดเดิม สอดคล้องกับหลักการเปิด-ปิด (open-closed principle)
- ลูกค้าสามารถเลือกใช้กลยุทธ์ที่แตกต่างกันตามความต้องการ สอดคล้องกับหลักการความรับผิดชอบเพียงคนเดียว (single responsibility principle)
- รูปแบบ Strategy มุ่งไปที่การให้ใช้ซ้ำได้ของอัลกอริทึมหรือพฤติกรรม หลีกเลี่ยงการทำซ้ำโค้ด
- รูปแบบ Strategy มุ่งไปที่การจัดระเบียบโค้ดที่ดีกว่า ทำให้โค้ดมีความชัดเจนและง่ายต่อการบำรุงรักษา
3. ตัวอย่างการประยุกต์ใช้รูปแบบ Strategy ในชีวิตจริง
รูปแบบ Strategy นั้นถูกนำไปใช้ในฐานะต่อไปนี้:
- วิธีการชำระเงินที่แตกต่างกัน เช่น Alipay, WeChat Pay, ฯลฯ
- อัลกอริทึมเรียงลำดับที่แตกต่างกัน เช่น การเรียงลำดับแบบ bubble sort, quicksort, ฯลฯ
- วิธีการบันทึกข้อมูลที่แตกต่างกัน เช่น การแสดงผลบนคอนโซล, การบันทึกข้อมูลลงในไฟล์, ฯลฯ
4. การประยุกต์ใช้รูปแบบ Strategy ใน Golang
ในส่วนนี้ เราจะประยุกต์ใช้รูปแบบ Strategy ใน Golang และให้ตัวอย่าง ไดอะแกรมคลาส UML และความคิดเห็นเกี่ยวข้อง และคอมเมนต์โค้ด
4.1. ไดอะแกรมคลาส UML
ด้านล่างนี้คือไดอะแกรมคลาส UML สำหรับรูปแบบ Strategy ใน Golang:
4.2. บทนำตัวอย่าง
จากไดอะแกรมคลาส UML ข้างต้น เราสามารถเห็นได้ว่ามีบทบาทสามอย่างของรูปแบบ Strategy: อินเทอร์เฟซ Strategy
, คลาสกลยุทธ์ที่ให้เห็น (เช่น ConcreteStrategyA
และ ConcreteStrategyB
), และคลาสคอนเท็กซ์ Context
ในตัวอย่างนี้ เราจะใช้การเลือกวิธีการชำระเงินสำหรับคำสั่งของระบบอีคอมเมิร์ซ เพื่ออธิบาย ผู้ใช้เลือกกลยุทธ์ที่เกี่ยวข้อง (ConcreteStrategyA
หรือ ConcreteStrategyB
) ตามวิธีการชำระเงิน และจากนั้นเรียกเมธอดของคลาสคอนเท็กซ์เพื่อชำระเงิน
4.3. ขั้นตอนการสร้าง 1: กำหนดอินเทอร์เฟซกลยุทธ์และคลาสกลยุทธ์ที่ให้เห็น
ต้องกำหนดอินเทอร์เฟซกลยุทธ์ Strategy
ที่รวมเมธอด Execute(data interface{}) string
เพื่อทำการดำเนินกลยุทธ์เฉพาะ
type Strategy interface {
Execute(data interface{}) string
}
type ConcreteStrategyA struct{}
func (s *ConcreteStrategyA) Execute(data interface{}) string {
// ตรรกะสำหรับการดำเนินกลยุทธ์เฉพาะ A
}
type ConcreteStrategyB struct{}
func (s *ConcreteStrategyB) Execute(data interface{}) string {
// ตรรกะสำหรับการดำเนินกลยุทธ์เฉพาะ B
}
4.4 ขั้นตอนการสร้าง 2: การสร้างคลาสคอนเท็กซ์
ต่อมา เราต้องการสร้างคลาสคอนเท็กซ์ Context
ซึ่งห่อหุ้มวัตถุกลยุทธ์เฉพาะ และให้เมธอด SetStrategy(strategy Strategy)
เพื่อกำหนดวัตถุกลยุทธ์ และเมธอด ExecuteStrategy(data interface{}) string
เพื่อดำเนินกลยุทธ์เฉพาะ
type Context struct {
strategy Strategy
}
func (c *Context) SetStrategy(strategy Strategy) {
c.strategy = strategy
}
func (c *Context) ExecuteStrategy(data interface{}) string {
if c.strategy == nil {
// ตรรกะดำเนินการ์ายเริ่มต้นเรื่องกลยุทธ์
} else {
return c.strategy.Execute(data)
}
}
4.5. ขั้นตอนการสร้าง 3: การใช้รูปแบบ Strategy เพื่อดำเนินการกิจกรรมทางธุรกิจจริง
ท้ายที่สุด เราสามารถนำรูปแบบ Strategy ไปใช้ในไคลเอ้นท์เพื่อดำเนินการงานทางธุรกิจจริง
func main() {
context := &Context{}
// กำหนดกลยุทธ์ที่เฉพาะ A โดยใช้เมธอด SetStrategy
context.SetStrategy(&ConcreteStrategyA{})
result := context.ExecuteStrategy("การชำระเงินด้วย Alipay")
// กำหนดกลยุทธ์ที่เฉพาะ B โดยใช้เมธอด SetStrategy
context.SetStrategy(&ConcreteStrategyB{})
result = context.ExecuteStrategy("การชำระเงินด้วย WeChat Pay")
}
สรุป
ผ่านโค้ดตัวอย่างข้างต้น เราได้เรียนรู้การใช้รูปแบบ Strategy ใน Golang รูปแบบ Strategy ช่วยให้เราสามารถเลือกใช้ขั้นตอนวิธีหรือพฤติกรรมต่าง ๆ ตามสถานการณ์ที่แตกต่างกัน และมีที่วางโค้ดที่ดีกว่า ทำให้โค้ดมีความชัดเจนและง่ายต่อการบำรุงรักษา ในการพัฒนาจริง การใช้รูปแบบ Strategy อย่างมีเหตุผลสามารถทำให้ความสามารถในการขยายของรหัสและการบำรุงรักษาได้ถึงขีดสุด