Strategy — คืออะไร รูปแบบกลยุทธ์ใน iOS และ Android

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-18 เวลาอ่าน: 9 นาที

Strategy (กลยุทธ์) เป็นรูปแบบการออกแบบเชิงพฤติกรรมที่กำหนดกลุ่มของอัลกอริทึมที่สามารถสับเปลี่ยนกันได้และวางแต่ละอัลกอริทึมในคลาสแยกต่างหาก (Strategy) รูปแบบนี้อนุญาตให้เลือกอัลกอริทึมได้ทันที: โค้ดของไคลเอนต์ทำงานผ่านอินเทอร์เฟซ Strategy ร่วมกัน และการนำไปใช้เฉพาะจะถูกแทนที่ในรันไทม์ ใน iOS รูปแบบนี้ถูกนำไปใช้ผ่าน Protocol + คลาสกลยุทธ์ ใน Android — ผ่าน Interface + การนำไปใช้ Strategy เป็นหนึ่งใน 23 รูปแบบ GoF ใช้กันอย่างแพร่หลายสำหรับการประมวลผลการชำระเงิน การตรวจสอบความถูกต้อง การเรียงลำดับ และการกรองข้อมูล สำหรับรายละเอียดเพิ่มเติม — ดูคำอธิบายดั้งเดิมของ GoF

ประเด็นสำคัญ

  • Strategy — รูปแบบพฤติกรรม GoF สำหรับกลุ่มของอัลกอริทึมที่สามารถสับเปลี่ยนกันได้
  • การห่อหุ้มอัลกอริทึม — แต่ละอัลกอริทึมถูกแยกอยู่ในคลาสของตัวเอง
  • อินเทอร์เฟซ Strategy — สัญญาร่วมที่กลยุทธ์รูปธรรมทั้งหมดนำไปใช้
  • องค์ประกอบแทนการสืบทอด — บริบทเก็บการอ้างอิงไปยังกลยุทธ์ ไม่ได้สืบทอดพฤติกรรม
  • หลักการ Open/Closed — สามารถเพิ่มกลยุทธ์ใหม่ได้โดยไม่ต้องเปลี่ยนโค้ดที่มีอยู่

รูปแบบ Strategy คืออะไร: แก่นสารและโครงสร้าง

Strategy เป็นหนึ่งใน 23 รูปแบบ GoF (Gang of Four) ที่อธิบายไว้ในหนังสือ "Design Patterns: Elements of Reusable Object-Oriented Software" (1994) รูปแบบนี้แก้ปัญหาการเลือกอัลกอริทึมในรันไทม์ แทนที่จะเขียนคลาสเดียวที่มีคำสั่งเงื่อนไขมากมาย (if-else, switch) Strategy เสนอให้แยกแต่ละอัลกอริทึมออกเป็นคลาสแยกต่างหากที่มีอินเทอร์เฟสร่วมกัน บริบท (คลาสที่ใช้กลยุทธ์) เก็บการอ้างอิงไปยังอินเทอร์เฟซ Strategy และมอบหมายการทำงานให้กับกลยุทธ์รูปธรรม

โครงสร้างของรูปแบบ ประกอบด้วยสามองค์ประกอบ: Context (บริบท) เก็บการอ้างอิงไปยัง Strategy และเรียกเมธอดของมัน; Strategy (อินเทอร์เฟซ) ประกาศเมธอดร่วมสำหรับอัลกอริทึมทั้งหมด; ConcreteStrategy (กลยุทธ์รูปธรรม) นำอินเทอร์เฟซไปใช้และมีอัลกอริทึมรูปธรรม ไคลเอนต์สร้างกลยุทธ์ที่ต้องการและส่งต่อไปยังบริบทผ่านคอนสตรัคเตอร์ ตัวตั้งค่า หรือพารามิเตอร์เมธอด บริบทไม่รู้ว่ากลยุทธ์เฉพาะใดกำลังถูกดำเนินการ — มันทำงานกับอินเทอร์เฟซเท่านั้น

องค์ประกอบบทบาทตัวอย่าง
Contextเก็บการอ้างอิงไปยัง StrategyPaymentProcessor, Sorter
Strategyอินเทอร์เฟสร่วมสำหรับอัลกอริทึมProtocol PaymentStrategy
ConcreteStrategyการนำอัลกอริทึมไปใช้รูปธรรมCardPayment, PayPalPayment

หลักการ Open/Closed — ข้อได้เปรียบหลักของ Strategy ระบบเปิดให้ขยายได้ (สามารถเพิ่มกลยุทธ์ใหม่) และปิดให้แก้ไข (โค้ดบริบทไม่จำเป็นต้องเปลี่ยน) หากไม่มีรูปแบบ การเพิ่มอัลกอริทึมใหม่จำเป็นต้องเปลี่ยนคลาสที่มีอยู่ ซึ่งละเมิด OCP และเพิ่มความเสี่ยงของข้อผิดพลาดจากการถดถอย Strategy ยังลดขนาดของคลาส: แทนที่คลาส 200 บรรทัดที่มี switch-case คุณจะได้ 6 คลาส ๆ ละ 20 บรรทัด

Strategy ใน iOS: การนำไปใช้ใน Swift ด้วย Protocol

Strategy ใน Swift ถูกนำไปใช้ผ่าน Protocol (อินเทอร์เฟซกลยุทธ์) และคลาสหรือโครงสร้างกลยุทธ์ โปรโตคอลของ Swift รองรับประเภทที่เกี่ยวข้องและข้อจำกัดเจนเนอริก ซึ่งให้ความยืดหยุ่นเมื่อออกแบบกลยุทธ์ บริบทมักจะเป็นคลาส ViewModel หรือบริการที่ยอมรับกลยุทธ์ใน init หรือผ่านคุณสมบัติ รูปแบบนี้ใช้กันอย่างแพร่หลายในโครงการ iOS สำหรับการจัดการเหตุการณ์ อนิเมชัน การจัดรูปแบบข้อมูล และกลยุทธ์ UI

swift
// 1. Protocol Strategy
protocol PaymentStrategy {
    func pay(amount: Decimal) async throws -> PaymentResult
}

// 2. Concrete Strategies
struct CardPaymentStrategy: PaymentStrategy {
    let cardNumber: String
    let cvv: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // ส่งคำขอไปยัง API ธนาคาร
        return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
    }
}

struct PayPalPaymentStrategy: PaymentStrategy {
    let email: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // เปลี่ยนเส้นทางไปยัง PayPal SDK
        return PaymentResult(status: .success, transactionId: "pp_\(UUID())")
    }
}

// 3. Context
class PaymentProcessor {
    private var strategy: PaymentStrategy

    init(strategy: PaymentStrategy) {
        self.strategy = strategy
    }

    func setStrategy(_: PaymentStrategy) {
        strategy = strategy
    }

    func processPayment(amount: Decimal) async throws -> PaymentResult {
        return try await strategy.pay(amount: amount)
    }
}

// การใช้งาน
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)

Strategy ใน SwiftUI — รูปแบบผสานรวมกับ MVVM ได้อย่างเป็นธรรมชาติ ViewModel มีคุณสมบัติกลยุทธ์และเรียกเมธอดของมันเมื่อผู้ใช้ดำเนินการ SwiftUI View รับข้อมูลผ่าน @Published หรือ @State — กลยุทธ์ซ่อนรายละเอียดการนำไปใช้จาก View ตัวอย่างเช่น กลยุทธ์การตรวจสอบความถูกต้องของข้อความ (emailValidator, phoneValidator) จะถูกสับเปลี่ยนตามประเภทของฟิลด์อินพุต การรวม Strategy กับ SwiftUI ให้ความยืดหยุ่นโดยไม่ต้องสืบทอดจาก UIKit

Strategy ใน Android: การนำไปใช้ใน Kotlin ด้วย Interface

Strategy ใน Kotlin ใช้ Interface ในระดับภาษาและอินเทอร์เฟซเชิงฟังก์ชัน (SAM) เพื่อความเรียบง่าย Kotlin รองรับแลมบ์ดา ซึ่งอนุญาตให้ส่งผ่านอัลกอริทึมเป็นฟังก์ชันโดยไม่ต้องประกาศคลาสกลยุทธ์แยกต่างหาก ใน Android รูปแบบนี้ใช้ใน ViewModel และ Use Cases เพื่อแยกอัลกอริทึมการโหลดข้อมูล การแคช และการจัดการข้อผิดพลาด โครงการ Android ที่ใช้ Clean Architecture ใช้ Strategy เพื่อฉีดการนำที่เก็บข้อมูลไปใช้ต่างกันตามแฟล็ก (mock, real, cache)

kotlin
// 1. Interface Strategy
interface PaymentStrategy {
    suspend fun pay(amount: BigDecimal): PaymentResult
}

// 2. Concrete Strategies
class CardPaymentStrategy(
    private val cardNumber: String,
    private val cvv: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // API ธนาคารผ่าน Retrofit
        return PaymentResult(success = true, transactionId = "tx_${UUID.randomUUID()}")
    }
}

class PayPalPaymentStrategy(
    private val email: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // การรวม PayPal SDK
        return PaymentResult(success = true, transactionId = "pp_${UUID.randomUUID()}")
    }
}

// 3. Context
class PaymentProcessor(
    private val strategy: PaymentStrategy
) {
    fun setStrategy(strategy: PaymentStrategy): PaymentProcessor {
        return PaymentProcessor(strategy)
    }

    suspend fun processPayment(amount: BigDecimal): PaymentResult {
        return strategy.pay(amount)
    }
}

// การใช้งานใน ViewModel
class CheckoutViewModel : ViewModel() {
    private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))

    fun payWithCard() {
        viewModelScope.launch {
            val result = processor.processPayment(BigDecimal("99.99"))
            // การประมวลผลผลลัพธ์
        }
    }
}

Strategy กับ Hilt/Dagger — ในโครงการ Android กลยุทธ์มักถูกฉีดผ่าน DI Hilt ให้การนำ PaymentStrategy ไปใช้รูปธรรมผ่าน @Binds หรือ @Provides สิ่งนี้อนุญาตให้เปลี่ยนกลยุทธ์โดยไม่ต้องแก้ไขโค้ดบริบท — เพียงเปลี่ยนโมดูล DI สำหรับบิลด์อื่น (debug/release) ตัวอย่างเช่น MockPaymentStrategy ถูกฉีดสำหรับการดีบัก กลยุทธ์ธนาคารจริงสำหรับการผลิต การรวม Strategy + DI ให้ความยืดหยุ่นสูงสุด

การเปรียบเทียบ Strategy กับ State, Command และ Template Method

Strategy vs State — โครงสร้างรูปแบบเหมือนกัน: ทั้งสองใช้องค์ประกอบกับอินเทอร์เฟซและคลาสรูปธรรม ความแตกต่างอยู่ที่วัตถุประสงค์: Strategy เลือกอัลกอริทึมอิสระ State ควบคุมพฤติกรรมของวัตถุตามสถานะของมัน ใน State บริบทเองเปลี่ยนกลยุทธ์เมื่อสถานะเปลี่ยน; ใน Strategy บริบทไม่ได้ควบคุมการสับเปลี่ยน — ไคลเอนต์กำหนดอัลกอริทึมอย่างชัดเจน กลยุทธ์ไม่รู้จักกันและกัน ในขณะที่สถานะสามารถเปลี่ยนผ่านระหว่างกันได้

Strategy vs Command — Command ห่อหุ้มการกระทำเดียวเป็นวัตถุ Strategy ห่อหุ้มชุดของอัลกอริทึมที่สามารถสับเปลี่ยนกันได้ Command คือ "ทำอะไร" (การเรียก execute ครั้งเดียว) Strategy คือ "ทำอย่างไร" (อัลกอริทึมหลายขั้นตอน) Command ใช้สำหรับคิว การดำเนินการล่าช้า เลิกทำ/ทำซ้ำ Strategy ใช้สำหรับเลือกวิธีทำงานในรันไทม์ คำสั่งสามารถกำหนดพารามิเตอร์ด้วยกลยุทธ์ รวมทั้งสองรูปแบบเข้าด้วยกัน

คุณลักษณะStrategyStateCommandTemplate Method
วัตถุประสงค์อัลกอริทึมที่สับเปลี่ยนกันได้พฤติกรรมตามสถานะการห่อหุ้มคำขอโครงร่างอัลกอริทึม
การเปลี่ยนโดยไคลเอนต์อย่างชัดเจนโดยบริบทอัตโนมัติโดยไคลเอนต์หรือคิวโดยการสืบทอด
ระดับวัตถุ (องค์ประกอบ)วัตถุ (องค์ประกอบ)วัตถุคลาส (การสืบทอด)

Strategy vs Template Method — ทั้งสองรูปแบบกำหนดอัลกอริทึมแต่ในวิธีที่ต่างกัน Template Method ใช้การสืบทอด: คลาสพื้นฐานกำหนดโครงร่างของอัลกอริทึม (เมธอดเทมเพลต) คลาสย่อยแทนที่ขั้นตอนแต่ละขั้นตอน Strategy ใช้องค์ประกอบ: อัลกอริทึมถูกแยกออกไปยังคลาสแยกต่างหากโดยสมบูรณ์ Template Method ง่ายกว่าสำหรับกรณีที่มีโครงสร้างอัลกอริทึมตายตัว Strategy — เมื่ออัลกอริทึมแตกต่างกันโดยสิ้นเชิงและสามารถเปลี่ยนแบบไดนามิก

ตัวอย่างการใช้งานจริงของรูปแบบ Strategy

การประมวลผลการชำระเงิน — ตัวอย่างคลาสสิกของ Strategy ตะกร้าสินค้าของร้านค้าออนไลน์มีรายการสินค้า และวิธีการชำระเงินถูกเลือกโดยผู้ใช้ แต่ละวิธี (บัตร, PayPal, Apple Pay, Google Pay, สกุลเงินดิจิทัล) เป็นกลยุทธ์แยกต่างหากที่มีลายเซ็น pay(amount) ร่วมกัน บริบท PaymentProcessor ไม่รู้ว่าการชำระเงินถูกประมวลผลอย่างไร — มันเรียกเมธอดร่วม การเพิ่มวิธีการชำระเงินใหม่ไม่จำเป็นต้องเปลี่ยนโค้ดตะกร้าสินค้า

การตรวจสอบความถูกต้องของข้อมูล — Strategy ใช้สำหรับกฎการตรวจสอบความถูกต้องต่างกันของฟิลด์เดียวกัน EmailValidatorStrategy, PhoneValidatorStrategy, AgeValidatorStrategy นำอินเทอร์เฟซ ValidationStrategy ร่วมกับเมธอด validate(input) ไปใช้ ฟอร์มลงทะเบียนใช้ชุดกลยุทธ์เพื่อตรวจสอบแต่ละฟิลด์ กลยุทธ์การตรวจสอบความถูกต้องสามารถรวมในห่วงโซ่ (Chain of Responsibility) หรือใช้ทั้งหมดพร้อมกันในลูป สิ่งนี้แทนที่การตรวจสอบ if-else ยาวด้วยชุดของตัวตรวจสอบความถูกต้องแบบพหุสัณฐาน

swift
// กลยุทธ์การเรียงลำดับ
protocol SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] where T: Comparable
}

struct QuickSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* quicksort */ items }
}

struct MergeSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* mergesort */ items }
}

class SortedDataSource<T> {
    private var strategy: SortingStrategy
    func display(_ items: [T]) { let sorted = strategy.sort(items) }
}

การรับรองความถูกต้อง — ในแอปมือถือ กลยุทธ์การรับรองความถูกต้องจะถูกสับเปลี่ยนตามผู้ให้บริการ AuthStrategy ด้วยเมธอด login(), logout(), getToken() ถูกนำไปใช้สำหรับ EmailPasswordAuth, GoogleAuth, AppleAuth, BiometricAuth บริบท AuthManager ยอมรับกลยุทธ์ผ่าน DI หรือโรงงาน สิ่งนี้อนุญาตให้เพิ่มผู้ให้บริการรับรองความถูกต้องใหม่โดยไม่ต้องเปลี่ยนหน้าจอเข้าสู่ระบบ รูปแบบ Strategy เป็นพื้นฐานสำหรับไลบรารี OAuth จำนวนมากและ Firebase Authentication

คำถามที่พบบ่อย

เมื่อใดควรใช้ Strategy แทน if-else?

Strategy เหมาะสมเมื่อคุณมี 3+ อัลกอริทึมที่อาจเปลี่ยนแปลงหรือขยายได้ หากมี 2 อัลกอริทึมและมีความเสถียร — if-else ง่าย ๆ มีต้นทุนน้อยกว่า ใช้ Strategy เมื่ออัลกอริทึมถูกใช้ในส่วนต่าง ๆ ของแอปพลิเคชัน เมื่อคุณต้องสับเปลี่ยนอัลกอริทึมในรันไทม์ หรือเมื่อแต่ละอัลกอริทึมต้องการ dependencies และการทดสอบของตัวเอง

Strategy เหมือนกับ State หรือไม่?

ไม่ มันเป็นรูปแบบที่แตกต่างกันที่มีโครงสร้างคล้ายกัน Strategy — ไคลเอนต์เลือกอัลกอริทึมอย่างชัดเจน และกลยุทธ์เป็นอิสระ State — วัตถุเปลี่ยนพฤติกรรมของมันเองเมื่อสถานะภายในเปลี่ยนแปลง และสถานะสามารถเปลี่ยนผ่านระหว่างกันได้ ใน State บริบทจัดการการเปลี่ยนแปลงสถานะ; ใน Strategy โค้ดไคลเอนต์จัดการ

สามารถใช้ Strategy โดยไม่มีคลาส — ผ่าน closures ได้หรือไม่?

ได้ ใน Swift และ Kotlin กลยุทธ์สามารถส่งผ่านเป็น closure หรือ lambda Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult สิ่งนี้ทำให้โค้ดง่ายขึ้นสำหรับกรณีง่าย ๆ แต่สูญเสียการตั้งชื่อและเอกสารประกอบ สำหรับ 1-2 อัลกอริทึม closure ก็เพียงพอ; สำหรับ 4+ ควรใช้คลาสแยกต่างหาก

จะทดสอบรูปแบบ Strategy ได้อย่างไร?

แต่ละกลยุทธ์ถูกทดสอบด้วยการทดสอบหน่วยแยกต่างหากโดยใช้ dependencies จำลอง บริบทถูกทดสอบด้วยกลยุทธ์จำลอง — ตรวจสอบว่าบริบทเรียกเมธอดของกลยุทธ์และส่งพารามิเตอร์ที่ถูกต้อง ใน Swift ใช้ XCTest + โปรโตคอลสำหรับการจำลอง; ใน Kotlin ใช้ MockK หรือ Mockito ข้อได้เปรียบหลัก: แต่ละกลยุทธ์ถูกทดสอบแยกกันโดยไม่ต้องตั้งค่าที่ซับซ้อน

Strategy เป็นรูปแบบ GoF หรือไม่?

ใช่ Strategy เป็นหนึ่งใน 23 รูปแบบที่อธิบายไว้ในหนังสือ "Design Patterns: Elements of Reusable Object-Oriented Software" (Gamma, Helm, Johnson, Vlissides, 1994) มันอยู่ในกลุ่มรูปแบบพฤติกรรม ชื่ออื่น: Policy โค้ดตัวอย่างดั้งเดิมใน Smalltalk-80 มีให้ใน GoF ฉบับดั้งเดิม

สรุป

  • Strategy — รูปแบบพฤติกรรมสำหรับอัลกอริทึมที่สับเปลี่ยนกันได้ด้วยอินเทอร์เฟสร่วม
  • การห่อหุ้ม — แต่ละอัลกอริทึมถูกแยกในคลาสกลยุทธ์แยกต่างหาก
  • iOS Swift — การนำไปใช้ผ่าน Protocol, โครงสร้าง และ closures
  • Android Kotlin — การนำไปใช้ผ่าน Interface, lambda และ DI กับ Hilt
  • หลักการ Open/Closed — เพิ่มกลยุทธ์ใหม่โดยไม่เปลี่ยนบริบท
  • การประยุกต์ใช้ — การชำระเงิน, การตรวจสอบ, การเรียงลำดับ, การรับรองความถูกต้อง, การจัดรูปแบบ

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม