Design Pattern: Strategy & Observer

Chun Rapeepat
Chun
Published in
4 min readNov 26, 2018

Hello World~ กลับมาเขียนบล็อกอีกครั้งในรอบหลายเดือน พอดีว่าช่วงนี้จะสอบเรื่อง Design Pattern พอดี ก็เลยขอยกเรื่องนี้มาเขียนละกัน, มาเข้าเรื่องเลยดีกว่า

“Design pattern is a general repeatable solution to a commonly occurring problem in software design.”

ถ้าแปลเป็นภาษาคนง่ายๆมันก็คือ Template หรือ แนวทางในการแก้ปัญหาอะไรสักอย่าง ยกตัวอย่างเช่น สมมุติเราทำแอพมา พอแอพโตไปได้สักระยะ เริ่มมีปัญหาตรงที่เวลาจะเพิ่ม Feature อะไรใหม่ก็จะไปกระทบโค้ดหลายๆส่วน

แน่นอนว่าปัญหาแบบนี้ มันทำให้แอพเรา Scale ช้า เพราะเวลาจะเพิ่มอะไรใหม่ๆก็จะเสียเวลามาก ถ้าเจอปัญหาแบบนี้เราก็อาจจะไปหา Design Pattern ที่ช่วยให้เราสามารถเพิ่ม Feature ได้อย่างรวดเร็วโดยไม่จำเป็นต้องไปแตะโค้ดในส่วนอื่นๆ เป็นต้น

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

มีข้อดีก็มีข้อเสียเช่นกัน อย่างแรกที่อาจเกิดขึ้นได้คือการเลือกใช้ Design Pattern แบบไม่เหมาะสม ในบางครั้งเราไม่จำเป็นต้องใช้ Design Pattern ก็ได้ บางทีมันอาจจะเกินความจำเป็น แล้วก็ทำให้เสียเวลาในการเขียนโค้ด และอีกอย่างคือ คนในทีมอาจจะไม่ได้เข้าใจ Design Pattern เหมือนกันก็ได้ เพราะเอาจริงๆมันมีเยอะมาก เดี๋ยวสักพักก็มีคนคิดอะไรใหม่ๆออกมาละ

ซึ่งในบทความนี้จะขอเล่า อันที่มันน่าจะได้ใช้บ่อยๆ 2 ตัวพอ นั้นก็คือ Strategy Pattern กับ Observer Pattern ไปดูตัวแรกกันเลย 😎

The Strategy Pattern

“The strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime.”

Strategy Pattern คือ Pattern ที่ทำให้เราสามารถเปลี่ยนลักษณะการทำงานของโค้ด หรือ Algorithm ในขณะรันโปรแกรมอยู่ได้

ลองคิดเล่นๆ สมมุติว่าเราสร้าง Class Person ขึ้นมาไว้เก็บข้อมูลนักเรียนต่างๆ คราวนี้เราอยากให้มันสามารถที่จะ Export as JSON ได้ สิ่งที่เราทำก็คือ สร้าง Method เลยสิ export() ที่ return string ออกมา ตามนี้

พอเวลาล่วงเลยไปสักพัก ลูกค้ามาบอกว่า “ขอให้มัน export as XML ได้ด้วยดิ” สิ่งที่เราทำง่ายๆเลยก็คือ เปลี่ยนชื่อ export เป็น exportAsJSON() แล้วคราวนี้เราก็เขียน method เพิ่มอีกตัวคือ exportAsXML()

ซึ่งมันจะดีกว่าไหมถ้าเกิดว่าอะไรที่เราอยากจะเพิ่ม มันเป็นเหมือน Extension แบบอยากได้อะไรใหม่ก็แค่เขียนเพิ่มเข้าไป ไม่ต้องมาแก้โค้ดในตัว class Person ซึ่งคราวนี้เราจะลองใช้ Stategy Pattern กัน แล้วมาลองดูว่ามันแตกต่างกันยังไง

อันดับแรกเราก็สร้าง Interface ขึ้นมาก่อนตัวนึง ชื่อว่า ExportStrategy ซึ่งก็จะมี method ตัวนึงชื่อว่า export() ดังรูป

แล้วเราก็ไปแก้อะไรนิดหน่อยใน Class Person อันดับแรกคือ Field ที่เป็นตัวเก็บ ExportStrategy และอีกอย่างคือ method: setStrategy กับ method: export สุดท้ายก็จะได้หน้าตาประมาณนี้

ทั้งหมดนี้เป็นอันเรียบร้อยละ แล้วถามว่าเราจะเอาพวก Algorithm มาใช้งานได้ยังไง เช่นพวก Export as XML, JSON อะไรงี้ ก็ไม่ยาก เราก็แค่ต้องสร้าง class ที่ Implement ตัว ExportStrategy ขึ้นมา

แล้วจากนั้นก็โยนลงไปใน Method setStrategy หลังจากนั้นก็สามารถเรียกใช้งาน Method export ได้เลย EASY~

ถ้าเกิดอยากจะเพิ่ม Export as CSV หรืออะไรแบบนี้ก็จะง่ายละ เพราะเราก็แค่ สร้าง class ใหม่ แล้วเราก็ setStrategy จากนั้นก็ใช้งานได้เลย จะเห็นว่าเราไม่จำเป็นต้องแตะโค้ดที่ class Person เลยเราก็สามารถที่จะใส่ Algorithm ใหม่ๆลงไปรันได้ ซึ่งไอ้แบบนี้มันตรงกับสิ่งที่เรียกว่า Open/Closed Principle ที่กล่าวไว้ว่า

“software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”

ประมาณว่า Class เนี่ยมันควรจะเสริมโน้นเสริมนี่ลงไปได้นะ แต่ไม่ควรที่จะไปแก้ไขอะไรมันได้ ซึ่ง Principle นี้มันมาจาก SOLID Principle อีกที เกี่ยวกับเรื่อง Object-oriented design principle นี่หละ ลองไปอ่านเพิ่มเติมกันได้

The Observer Pattern

“The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.”

อันนี้เจ๋งขึ้นมาหน่อย ก่อนอื่นต้องของเล่าแบบนี้ก่อน สมมุติว่าเรามีโค้ดแบบนี้

Javascript; Google Chrome console

คือให้ x = 10 ให้ y = 10 แล้ว z = x + y แล้วคิดว่าผลลัพธ์จะออกมาเป็นเท่าไร???แน่นอนก็ต้องเป็น 20 อยู่แล้ว แล้วคราวนี้ถ้าเกิดผมแก้ x = 30 หละ แล้วลองพิมพ์ z ออกมาคิดว่า z จะเป็นเท่าไร 20 เหมือนเดิมหรือ 40??

Javascript; Google Chrome console

เป็น 20 เหมือนเดิม… ที่เป็นแบบนี้คือ Z มันเก็บค่าตอนแรกเอาไว้ แล้วพอ X เปลี่ยน Z ก็ไม่ได้รู้เรื่องอะไรด้วยก็เลยไม่ได้อัพเดรตตาม คราวนี้ Observer Pattern เลยบอกว่างั้นให้ X, Y เป็น Observable คือตัวที่สามารถมองเห็นได้ (รอให้คนอื่นมา subscribe) แล้วให้ Z มันไป subscribe เอาไว้ ประมาณว่า ถ้า X, Y ค่าเปลี่ยนเนี่ย มาเตือนกุด้วย

คราวนี้พอเราอัพเดรตค่าในตัวแปร X หรือไม่ก็ Y (Update state) ตัว Z มันก็จะได้รับ Notify ว่า X, Y ค่าเปลี่ยนแล้วนะ มันก็เลยคำนวนค่าของตัวเองใหม่ เป็นต้น ซึ่ง Concept ของ Observer Pattern ก็จะเป็นประมาณนี้ นิยมใช้กับพวก GUI (Graphic User Interface) ซะส่วนใหญ่ เช่นแบบแก้ไขค่า เพิ่มค่า หรือลบค่าอะไรในโค้ด มันก็จะไปอัพเดรตที่ UI ให้ทันที

ก่อนอื่นมีศัพท์ที่ต้องทำความเข้าใจเพิ่มหน่อยคือ Subject กับ Observer เริ่มจาก Observer ก่อน มันเหมือนเป็นตัวสังเกตการณ์อ่ะ คอยรอ Notify จากคนอื่น มี Method ตัวนึงชื่อว่า update (ถ้ามี notify มามันก็จะ call method update ให้)

ส่วน Subject เป็นตัวจัดการ Observer อันนี้จะเป็น Interface ที่เวลาจะใช้ต้อง Implement มันไป หลักๆจะมี Method คือ register observer, un-register observer, notify observers ก็คือเหมือนจะเพิ่ม ลบ หรือแจ้งเตือน Observer อะไรแบบนี้

สำหรับหลักการทำงานขอยกตัวอย่างเป็น Todolist App ละกัน สมมุติมี class นึงเป็น UI Controller ชื่อว่า TodolistController ละกัน เป็นตัวจัดการ UI แล้วก็มีอีก class นึงชื่อว่า Todolist เป็นตัวเก็บพวก tasks ทั้งหลายอ่ะ แบบวันนี้ทำไรดีโน้นนี่นั้น อาจจะเก็บเป็น LinkedList หรือ Array ก็ได้

เราจะให้ TodolistController Implement Observer เพราะว่าเป็นตัวสังเกตุดูว่า มีข้อมูลอะไรเพิ่มมารึป่าว ถ้ามีก็จะได้อัพเดรต

ส่วนตัว Todolist ก็จะให้ Implement Subject เพราะเป็นตัว Observable ที่ TodolistController ต้องมา subscribe รอรับ Notification

ถ้าลองสังเกตุใน method addTask หลังจากเพิ่มข้อมูลเรียบร้อยแล้วเราจะทำการ Notify observers ทุกตัวที่ subscribe ไว้ เพื่อบอกให้ทุกคนรู้ว่ามีการเพิ่ม หรือมีการอัพเดรตแล้วนะ ปล. ตอนใช้งานอย่าลืม register observer นะ registerObserver(todolistController) อะไรงี้

ในส่วนของโค้ดแบบละเอียดลองไปค้นดูกันเองได้เลยนะ เพราะว่ามันน่าจะค่อนข้างยาว อันนี้เขียนสั้นๆมายกตัวอย่างให้เห็นภาพกันเฉยๆ

สำหรับบทความนี้ก็ขอจบเท่านี้ละกันครับ ถ้าเกิดว่ามีข้อสงสัย อยากให้เพิ่มข้อมูล หรือแก้ไขอะไร ทักมาคุยกันได้นะครับ ที่ Facebook: Chun Rapeepat Bye~

--

--

Chun Rapeepat
Chun
Editor for

Indie hacker, entrepreneur, and Web3 researcher.