Saladpuk.com
🏆 เนื้อหาหลัก
🏆 เนื้อหาหลัก
  • 💖สลัดผัก
  • 📰มีอะไรใหม่บ้าง
    • 2020
      • 2020-11
      • 2020-10
      • 2020-09
      • 2020-08
      • 2020-03
      • 2020-02
      • 2020-01
    • 2019
      • 2019-12
      • 2019-11
      • 2019-10
      • 2019-09
      • 2019-08
  • 🤔อ่านเรื่องไรดี ?
  • มือใหม่หัดเขียนโค้ด
    • 👶เขียนโค้ดด้วยภาษา C#
      • เกิดมาไม่เคยเขียนโค้ดมาก่อนเบย
      • 👶พื้นฐาน
        • 1.โปรแกรมที่ต้องลง
        • 2.โครงสร้างของโค้ด
        • 3.ชนิดของข้อมูล
        • 4.การสร้างตัวแปร
        • 5.คำสั่งพื้นฐาน
        • 6.การแปลงข้อมูล
        • 7.การเปรียบเทียบค่า
        • 8.การตัดสินใจด้วย IF statements
        • 9.การตัดสินใจด้วย Switch statements
        • 10.การทำงานซ้ำๆด้วย While
        • 11.การทำงานซ้ำๆด้วย Do While
        • 12.การทำงานซ้ำๆด้วย For
        • 13.การแก้โจทย์จากรูป
        • 14.มารู้จักกับ Array กัน
      • 🧑ระดับกลาง
        • 15.Value type vs Reference type
        • 16.ลดงานซ้ำๆด้วย Method
        • 17.มารู้จักกับ Class & Field กัน
        • 18.มารู้จักกับ Constructor กันบ้าง
        • 19.มาเขียน Method ใน Class กัน
        • 20.มารู้จักกับ Property กัน
        • 21.ลองใช้คลาสแบบจริงจังบ้าง
        • 22.การสืบทอด Inheritance
        • 23.Polymorphism
        • 24.Abstract Class
        • 25.Interface
        • 26.Namespace
        • 27.Enum
        • 28.Exception handler
        • 29.ลงลึกกับ string
        • 30.StringBuilder เพื่อนคู่ string
      • 👨⏳ระดับสูง
        • Generic
        • Delegates
        • Action & Func
        • Lambda expression
        • LINQ
        • พระคัมภีร์การใช้คำสั่ง LINQ
      • 💡Tips
        • 💡C# version 8.0
        • 💡Boxing & Unboxing
    • 👶Algorithm
      • 👾Algorithm Big-O
      • 👽Algorithm P & NP
    • 👦OOP
      • 💖Abstraction
      • 💖Encapsulation
      • 🏆Abstraction & Encapsulation
      • 💖Inheritance
      • 💖Polymorphism
      • 🏆Inheritance & Polymorphism
      • 📝ลองเขียน OOP ดูดิ๊
      • 👑OOP + Power of Design
      • 🥰เทคนิคในการออกแบบ
    • 👶บทสรุปฐานข้อมูล
      • เก็บรูปในฐานข้อมูล
      • Database indexing
      • การลบข้อมูล
    • 👦Communication Patterns
    • 👦Design Patterns
      • 🤰Creational Patterns
        • 🏭Factory Method
        • 🏭Abstract Factory
        • ☝️ Singleton Pattern
        • 🏗️ Builder Pattern
        • 🎎Prototype Pattern
      • 🧱Structural Patterns
        • 🔌Adapter Pattern
        • 📪Proxy Pattern
  • Puzzle
    • 🧠Challenges
      • 🐴Google ม้า 25 ตัว
      • 🌉Amazon เสา 2 ต้น
      • 🥇ทองเก๊
      • 💊ยาต้านโควิด
      • 🎩CP หมวก 5 ใบ
      • 🧓Einstein's Riddle 01
  • พื้นฐานที่ควรต้องรู้
    • 🐳Docker
      • 📦Docker Containers
      • 🃏Docker Exercise 01
      • 🛠️ Docker Tools
      • 🗃️ Docker Registry
      • 🖼️ Container Image
      • 📢Docker Push
      • 🔄WSL
    • 👶Clean Code
      • 🧓Uncle Bob - Clean Code
      • 🧓Uncle Bob - Comments
      • 🧓Uncle Bob - Naming
      • 🧓Uncle Bob - Mindset
      • 🧓Uncle Bob - TDD
    • 👶Code Smells
    • 👶สิ่งที่คนเขียนโค้ดมักเข้าใจผิด
    • 👶AI พื้นฐาน
    • 👶Git พื้นฐาน
      • Git branching strategy
    • 👶Cloud พื้นฐาน
    • 👶UML พื้นฐาน
      • Activity Diagram
      • Class Diagram
      • Sequence Diagram
      • Use case Diagram
      • บทสรุปการใช้ UML
    • 👶Data Scientist
      • การเลือก Algorithms ให้ AI (1/5)
      • การเตรียมข้อมูลให้ AI (2/5)
      • หลักการตั้งคำถามให้ AI (3/5)
      • แฉความลับของ AI Model (4/5)
      • หัดเขียน AI จาก AI ของคนอื่น (5/5)
    • 👶DevOps พื้นฐาน
    • 👶Docker ขั้นพื้นฐาน
      • Image and Container
      • แชร์ Docker Image ที่สร้างไว้
    • 👶Microservices พื้นฐาน
      • Microservices ที่ดีมีลักษณะยังไง
      • Microservices Tips
      • จาก Monolith สู่ Microservices
    • 👶ความรู้พื้นฐานในการทำเว็บ
    • 👦Bottlenecks of Software
      • หัวใจที่สำคัญที่สุดของฐานข้อมูล
    • 👦Agile Methodology
      • Agile in a Nutshell
      • Software Development Life Cycle
      • Code Review
    • 👦Security พื้นฐาน
      • การเก็บรหัสผ่านที่ถูกต้อง
      • Security in actions
        • Hash function
      • Security Principles
      • 😎The Matrix 1
      • 😎The Matrix 2
      • HTTPS in a nutshell
    • 👦SOLID Design Principles
      • มารู้จักกับ SOLID กันดีกว่า
      • Single-Responsibility Principle
      • Open/Closed Principle
      • Liskov Substitution Principle
      • Interface Segregation Principle
      • Dependency-Inversion Principle
  • Cloud Computing
    • 👶Microsoft Azure 101
      • สมัคร Microsoft Azure
      • รู้จักกับ Resource Groups
      • สร้างเว็บตัวแรกกัน
      • สร้าง Virtual Machine กัน
      • ประเภทของคลาว์เซอร์วิส
      • มาสร้าง Logic App กัน
      • มาสร้าง Function App กัน
      • คลาว์คิดเงินยังไง ?
      • Cloud Native
      • Guideline for Cloud scaling
      • Auto Scaling
    • 👶Azure App Services
    • 👶App Service Plan
    • 👶Azure Storage
      • Blob storage
        • ลองสร้างที่เก็บไฟล์กันเลย
        • เข้าใจ Blob storage ให้มากขึ้น
        • ลองเขียนโค้ดอัพโหลดไฟล์กันบ้าง
        • สร้างเว็บจากที่ฝากไฟล์บนคลาว์
    • 👶Azure Bot Service
      • Bot เข้าใจเราได้ยังไงกันนะ
    • 👶Azure Cognitive Services
      • การสร้าง Cognitive Services
      • การ Login ด้วยใบหน้า
      • อ่านลายมือจากรูปเป็นตัวอักษร (OCR)
      • เขียน AI แยกของต่างๆทำยังไง?
      • เขียนแอพ ทายอายุ บอกเพศ ง่ายจิ๊ดเดียว
      • เขียนแอพให้ AI อธิบายรูปเป็นภาษาคน
    • 👶Machine Learning Studio
      • มาสร้าง AI ของแท้ตัวแรกของเรากัน
      • สร้าง AI ตัดสินใจอนุมัติบัตรเครดิต 💳
      • ลองเรียกใช้ AI ของเรากัน
    • 👶Azure Service Fabric
      • สร้าง Service Fabric กัน
    • 👶Blockchain
      • Blockchain ทำงานยังไง ?
      • Consensus Algorithm คืออะไร ?
      • สร้าง Blockchain ใช้เองกัน !
      • หัดเขียน Smart Contract กัน
    • 👶Power BI
    • 👶Azure Web App
      • เซิฟเวอร์บนคลาว์ ราคา? ต่าง?
    • 👶Azure DevOps
      • เล่น Azure DevOps กัน
      • เล่นกับ Repository
      • ลองทำ Continuous Integration (CI)
      • ลองทำ Continuous Delivery (CD)
      • เล่น Kanban Board
    • 🤠Cloud Playground
      • การป้องกันความลับหลุดตอนที่ 1
      • การป้องกันความลับหลุดตอนที่ 2
      • การป้องกันความลับหลุดตอนที่ 3
      • การป้องกันความลับหลุดตอนจบ
  • Software Testing
    • 👦Test-First Design
    • 👦Test-Driven Development
      • 1.มารู้จักกับ TDD กันดีกว่า
      • 2.Test cases เขาเขียนกันยังไงนะ
      • 3.เครื่องมือในการทดสอบ
      • 4.การใช้ Theory และ InlineData
      • 5.โค้ดที่ทดสอบได้
      • 6.Mantra of TDD
      • 7.Functional & None-Functional testing
      • 8.Manual vs Automation testing
      • 9.Automation Frameworks in .NET
      • 10.Mock Framework
      • 11.มาเรียนการใช้ Moq กันเถอะ
      • 12.สรุป
  • Web
    • 👦Web API
      • 1.Web API คืออะไร
      • 2.ติดตั้ง .NET Core SDK
      • 3.สร้าง Web API ตัวแรกกัน
      • 4.Verbs
      • 5.Swagger เพื่อคู่ API
      • 6.การใช้ Model
      • 7.เรียก Web API ผ่าน Postman
      • 8.มาจัดกลุ่ม API กัน (1/2)
      • 9.มาจัดกลุ่ม API กัน (2/2)
  • Software Design
    • 🤴Design Patterns
      • 🦈Creational patterns
        • Abstract Factory
        • Builder
        • Factory Method
        • Prototype
        • Singleton
      • 🦈Structural patterns
        • Adapter
        • Bridge
        • Decorator
        • Facade
        • Proxy
      • 🦈Behavioral patterns
        • Chain of Responsibility
        • Command
        • Iterator
        • Mediator
        • Memento
        • Observer
        • State
        • Strategy
        • Template Method
        • Visitor
Powered by GitBook
On this page
  • Strategy
  • 🎯 เป้าหมายของ pattern นี้
  • ✌ หลักการแบบสั้นๆ
  • 😢 ปัญหา
  • 😄 วิธีแก้ไข
  • 📌 โครงสร้างของ pattern นี้
  • 🛠 ตัวอย่างการนำไปใช้งาน
  • 👍 ข้อดี
  • 👎 ข้อเสีย
  • ‍‍📝 Code ตัวอย่าง

Was this helpful?

Export as PDF
  1. Software Design
  2. Design Patterns
  3. Behavioral patterns

Strategy

PreviousStateNextTemplate Method

Last updated 5 years ago

Was this helpful?

Strategy

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

🎯 เป้าหมายของ pattern นี้

สร้างการทำงานหลายๆแบบ เพื่อให้ client เลือกไปใช้งานตามความเหมาะสม

✌ หลักการแบบสั้นๆ

  1. แยกงานเฉพาะเรื่องที่แตกต่างกันออกเป็นหลายๆ class

  2. สร้าง interface กลางของงานที่แยกออกมา

  3. ตัวทำงานให้ reference interface นั้น

  4. ให้ client เป็นคนกำหนดว่าจะสร้าง object เพื่อเอาไว้ทำงานจาก class ไหน

😢 ปัญหา

สมมุติว่าเรากำลังเขียนโปรแกรมแผนที่ตัวนึง เพื่อเอาไปแข่งกับ Google map และตอนนี้ตัวโปรแกรมมีแค่ Navigator class เท่านั้น

หัวใจสำคัญของโปรแกรมตัวนี้คือ มันสามารถคำนวณเส้นทางที่ใกล้ที่สุดให้เราได้ แล้วมันก็จะแสดงเป็นแผนที่สวยงามบนมือถือให้เราดู

ในเวอร์ชั่นแรกมันสามารถคำนวณการเดินทางด้วย รถยนต์ ได้เท่านั้น แต่หลังจากเปิดตัวโปรแกรมนี้ไปซักพัก ผู้ใช้ก็เริ่มบ่นว่าอยากให้มันบอกการเดินทางด้วยวิธีอื่นๆด้วย

ดังนั้นในเวอร์ชั่นสอง เราเลยเพิ่มความสามารถให้มันคำนวณการเดินทางด้วย ทางเท้า, ทางรถไฟ,รถไฟฟ้า และ รถประจำทางต่างๆ เข้าไปด้วย เพื่อให้กับคนเดินถนนสามารถไปถึงจุดหมายได้เร็วที่สุด

โปรแกรมทำงานต่างๆได้ด้วยดี ผู้ใช้ Happy เงินเดือนเพิ่มขึ้น และตามมาด้วยความปวดหัวของโปรแกรมเมอร์ เพราะเจ้า Navigatorclass เริ่มบวมขึ้นเรื่อยๆ

และแล้วจุดแตกหักก็มาถึง ในวันที่เราเพิ่มการเดินทางด้วย รถจักรยาน เข้าไป ตัวโปรแกรมเริ่มแสดงผลแปลกๆเช่น แนะนำให้รถขับไปบนทางรถไฟ แนะนำให้คนไปเดินบนไฮเวย์ หรือให้รถจักรยานปั่นลงน้ำ!! (เป็นก้าวพัฒนาที่ดีนะ เพราะ Apple เวอร์ชั่นแรกๆก็มี feature นี้ให้คนพูดถึงเหมือนกัน)

เหล่าผู้บริหารโวยวายกันออฟฟิสแตก ถามหาว่าเกิดอะไรขึ้น ในขณะที่ developer นั่งหา bugs กันหัวหมุน

ทุกครั้งที่เพิ่มวิธีการเดินทางแบบใหม่ลงไป พี่ Navigator class ก็จะตัวบวมขึ้น งานที่เคยใช้ได้กลับใช้ไม่ได้ ทำให้มักจะมีปัญหาตามมาเสมอๆ (คุ้นๆวุ้ย เหมือนตอนยังไม่รู้จัก TDD เลย)

ขณะที่เรากำลังหาว่าเกิดอะไรขึ้น ก็มีผู้บริหารคนหนึ่งขว้างนาฬิกาหนีนักข่าวที่จะเข้ามาทำข่าวของแอพของเรา ซึ่งเจ้านาฬิกาตัวซวยที่ยืมเพื่อนมาก็เข้ามาโดนหัวเราเข้าอย่างจัง จนหมดสติไป

😄 วิธีแก้ไข

ขณะที่สติเลือนลาง ก็มีภาพผุดขึ้นมาในหัว เป็นภาพเราขณะที่เดินทางไปเขาเหลียงซาน ก็ได้พบกับหลวงพ่อแห่งวัดอังโคะคุจิ ซึ่งท่านมีข้อแนะนำไว้ว่า ถ้าโยมมี class อะไรซักอย่าง ที่มันทำงานเฉพาะเรื่องของมัน แต่มีรูปแบบการทำงานที่แตกต่างกันหลายๆแบบ โยมจงแยกการทำงานพวกนั้นออกเป็น class หลายๆตัวแทนซะ ซึ่งเจ้า class ที่แยกออกมาเหล่านี้หลวงพ่อเรียกมันว่า Strategy

ส่วน class ตัวแรกนั้นหลวงพ่อขอเรียกมันว่า Context ซึ่งมันจะต้องมี field ที่ชี้กลับไปหา strategy ที่มันจะใช้ซักตัว เมื่อเข้า context จะต้องทำงาน มันก็แค่สั่งให้ strategy ไปทำงานแทนซะ

เจ้า context ไม่ได้มีหน้าที่บอกว่าจะใช้ strategy ตัวไหน แต่ client ต่างหากที่จะเลือก strategy ให้กับ context เอง ซึ่งจริงๆแล้ว context มันไม่รู้เลยด้วยซ้ำว่ามี strategy อะไรบ้าง มันทำงานกับ strategy ได้เพราะมันทำงานผ่าน interface นั่นเอง ด้วยเหตุนี้เองเลยทำให้เราสามารถเพิ่ม strategy ใหม่ๆเข้าไปได้เรื่อยๆ หรือแก้ไข strategy โดยที่ไม่มีผลกระทบกับ context หรือ strategy ตัวอื่นเลย

ปิ้ง!! หลังจากได้สติกลับมาและหายเมากาวแล้ว จึงรีบเอานาฬิกาซุกเข้ากระเป๋าซะ แล้วรีบตีเนียนโดยการหยิบกระดาษมาเขียนของที่เห็นเมื่อสักครู่ออกมา ตามภาพด้านล่าง

เดิมตัว Navigation ก็คือตัวที่ทำงานทุกอย่าง มันเลยบวมออกเรื่อยๆ ดังนั้นเราเลยทำการแยกงานของมันออกมาเป็น Strategryหลายๆตัว ทางรถ(RoadStrategy), ทางเท้า(WalkingStrategy), การขนส่งสาธารณะ(PublicTransportStrategy)

ดังนั้นตัว Navigation ของเราก็คือ Context ตามที่หลวงพ่อว่าไว้ ดังนั้นมันเลยต้อง reference ไปหา strategy ผ่าน interface ที่ชื่อว่า RouteStrategy

ส่วนเมื่อต้องการจะเดินทางด้วยรถยนต์ เราก็แค่ส่ง RoadStrategy object ไปให้กับ Navigation class ทำงานด้วย และเมื่อไหร่จะเดินทางด้วยเท้า เราก็ส่ง WalkingStrategy object ไปให้เท่านั้น

จากที่เมากาวมา จะเห็นว่า ตัว Navigation ตัวเดิม สามารถเปลี่ยนการทำงานไปได้เรื่อยๆ เพียงแค่เราเปลี่ยน strategy เท่านั้นเอง

📌 โครงสร้างของ pattern นี้

อธิบาย 1.Context - เป็นตัวที่อ้างถึง strategy ผ่าน interface เพื่อทำงานด้วยเมื่อ client เรียก 2.Strategy interface - เป็นแบบอย่างให้กับ strategy ต่างๆ และมันจะมี method เพื่อให้ context สามารถเรียกใช้งานได้ 3.Concrete Strategies - ตัวที่ทำงานจริงๆ ซึ่งส่วนใหญ่เราจะมี strategy หลายตัว เพื่อให้สามารถทำงานได้หลายๆแบบที่ต่างกัน เมื่อ client เรียก context ทำงาน ตัว context จะสั่งให้ strategy ทำงานให้ 4.Client - เป็นคนส่ง strategy ที่จะใช้ให้กับ context

🛠 ตัวอย่างการนำไปใช้งาน

ในเกมหลายๆเกมจะมีระบบธาตุ ซึ่งผู้เล่นสามารถเอาธาตุไปใส่อาวุธได้ ทำให้เวลาเวลาโจมตีออกไปจะทำให้เกิดผลที่ไม่เหมือนกัน

  • ธาตุไฟ จะโจมตีสูงขึ้นเมื่อเจอกับธาตุดิน แต่จะโจมเบาลงเมื่อโจมตีใส่ธาตุน้ำ

  • ธาตุน้ำ จะโจมตีสูงขึ้นเมื่อเจอกับธาตุไฟ แต่จะโจมตีเบาลงเมื่อโจมตีใส่ธาตุดิน

  • ธาตุดิน จะโจมตีสูงขึ้นเมื่อเจอกับธาตน้ำ แต่จะโจมตีเบาลงเมื่อโจมตีใส่ธาตุไฟ และผู้เล่นจะเปลี่ยนธาตุให้กับอาวุธของตัวเองเมื่อไหร่ก็ได้ อะไรประมาณนี้ ดังนั้นเราจะลองใช้ strategy pattern เข้ามาช่วย เพื่อให้อาวุธของผู้เล่นมีการทำงานหลายๆรูปแบบ ไปดูที่โค้ดตัวอย่างกันเลย

👍 ข้อดี

  • สามารถเปลี่ยนการทำงานได้ตลอดเวลา ขณะ runtime

  • แยกการทำงานออกเป็นเรื่องๆ ขาดจากกันได้

  • ถูกหลัก Open/Closed Principle

👎 ข้อเสีย

  • ถ้าการทำงานมีไม่เยอะและไม่ได้เปลี่ยนบ่อย อย่าใช้ strategy pattern มันทำให้โปรแกรมเราซับซ้อนขึ้นโดยไม่จำเป็น

  • Client จะต้องรู้ว่า strategy ที่จะใช้แต่ละตัวคืออะไร และต่างกันยังไง

  • ภาษา/framework สมัยใหม่ส่วนใหญ่จะรอบรับของพวกนี้อยู่แล้ว ไปศึกษาแล้วใช้ของพวกนั้นดีกว่าถ้าจะต้องใช้

‍‍📝 Code ตัวอย่าง

using System;

// Strategy Interface
interface IElement
{
    string Name { get; }
    void Attack(string element);
}

// Strategies
class EarthElement : IElement
{
    public string Name => "Earth";
    public void Attack(string element)
    {
        if(element == "Water") Console.WriteLine("attack+10");
        else if(element == "Fire") Console.WriteLine("attack-5");
        else Console.WriteLine("attack+0");
    }
}
class FireElement : IElement
{
    public string Name => "Fire";
    public void Attack(string element)
    {
        if(element == "Earth") Console.WriteLine("attack+10");
        else if(element == "Water") Console.WriteLine("attack-5");
        else Console.WriteLine("attack+0");
    }
}
class WaterElement : IElement
{
    public string Name => "Water";
    public void Attack(string element)
    {
        if(element == "Fire") Console.WriteLine("attack+10");
        else if(element == "Earth") Console.WriteLine("attack-5");
        else Console.WriteLine("attack+0");
    }
}

// Context
class Weapon
{
    public IElement Element { get; set; }

    public void Attack(string element)
    {
        Console.WriteLine($"โจมตีด้วยธาตุ {Element.Name} ใส่ธาตุ {element}");
        Element.Attack(element);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var weapon = new Weapon();
        weapon.Element = new FireElement();
        weapon.Attack("Earth");

        weapon.Element = new WaterElement();
        weapon.Attack("Earth");

        weapon.Element = new EarthElement();
        weapon.Attack("Water");
    }
}

Output

โจมตีด้วยธาตุ Fire ใส่ธาตุ Earth
attack+10
โจมตีด้วยธาตุ Water ใส่ธาตุ Earth
attack-5
โจมตีด้วยธาตุ Earth ใส่ธาตุ Water
attack+10

🤴
🦈
img
img
img
img