Strategy — ano ito, pattern ng estratehiya sa iOS at Android

May-akda: IT Sectr Nai-publish: 2026-02-18 Oras ng pagbabasa: 9 min

Strategy (Estratehiya) — isang pattern ng pag-uugali ng disenyo na tumutukoy sa isang pamilya ng mga mapagpapalit na algorithm at inilalagay ang bawat isa sa kanila sa isang hiwalay na klase (Strategy). Pinapayagan ng pattern ang pagpili ng algorithm sa mabilisang: ang client code ay gumagana sa pamamagitan ng isang karaniwang interface ng Strategy, at ang konkretong pagpapatupad ay inilalagay sa runtime. Sa iOS ang pattern ay ipinapatupad sa pamamagitan ng Protocol + mga klase ng estratehiya, sa Android — sa pamamagitan ng Interface + mga pagpapatupad. Strategy — isa sa 23 pattern ng GoF, malawakang ginagamit para sa pagproseso ng pagbabayad, pag-validate, pag-uuri at pag-filter ng data. Higit pa — sa orihinal na paglalarawan ng GoF.

Mahahalagang Punto

  • Strategy — pattern ng pag-uugali ng GoF para sa isang pamilya ng mga mapagpapalit na algorithm
  • Encapsulation ng mga algorithm — bawat algorithm ay nakahiwalay sa sarili nitong klase
  • Interface ng Strategy — ang karaniwang kontrata na ipinapatupad ng lahat ng konkretong estratehiya
  • Komposisyon sa halip na pamana — ang konteksto ay nag-iimbak ng referensya sa estratehiya, hindi nagmamana ng pag-uugali
  • Prinsipyo ng Open/Closed — ang mga bagong estratehiya ay idinaragdag nang hindi binabago ang umiiral na code

Ano ang pattern ng Strategy: esensya at istraktura

Strategy — isa sa 23 pattern ng GoF (Gang of Four), na inilarawan sa aklat na «Design Patterns: Elements of Reusable Object-Oriented Software» (1994). Nilulutas ng pattern ang problema ng pagpili ng algorithm sa runtime. Sa halip na magsulat ng isang klase na may maraming conditional operator (if-else, switch), iminumungkahi ng Strategy na ihiwalay ang bawat algorithm sa isang hiwalay na klase na may isang karaniwang interface. Ang konteksto (ang klase na gumagamit ng estratehiya) ay nag-iimbak ng referensya sa interface ng Strategy at nag-delegate ng pagpapatupad sa konkretong estratehiya.

Ang istraktura ng pattern ay may kasamang tatlong elemento: Context (konteksto) ay naglalaman ng referensya sa Strategy at tumatawag sa pamamaraan nito; Strategy (interface) ay nagdedeklara ng isang karaniwang pamamaraan para sa lahat ng algorithm; ConcreteStrategy (konkretong estratehiya) ay nagpapatupad ng interface at naglalaman ng konkretong algorithm. Ang client ay lumilikha ng kinakailangang estratehiya at ipinapasa ito sa konteksto sa pamamagitan ng constructor, setter, o parameter ng pamamaraan. Hindi alam ng konteksto kung aling estratehiya ang isinasagawa — gumagana lamang ito sa interface.

KomponentePapelHalimbawa
ContextNaglalaman ng referensya sa StrategyPaymentProcessor, Sorter
StrategyKaraniwang interface para sa mga algorithmProtocol PaymentStrategy
ConcreteStrategyKonkretong pagpapatupad ng algorithmCardPayment, PayPalPayment

Prinsipyo ng Open/Closed — pangunahing bentahe ng Strategy. Ang sistema ay bukas para sa pagpapalawak (maaaring magdagdag ng bagong estratehiya) at sarado para sa pagbabago (hindi kailangang baguhin ang code ng konteksto). Kung wala ang pattern, ang pagdaragdag ng bagong algorithm ay nangangailangan ng pagbabago sa umiiral na klase, na lumalabag sa OCP at nagpapataas ng panganib ng mga regression error. Binabawasan din ng Strategy ang laki ng mga klase: sa halip na isang 200-linya na klase na may switch-case, makakakuha ka ng 6 na klase na tig-20 linya bawat isa.

Strategy sa iOS: pagpapatupad sa Swift gamit ang Protocol

Strategy sa Swift ay ipinapatupad sa pamamagitan ng Protocol (interface ng estratehiya) at mga klase o istraktura ng estratehiya. Ang mga protocol ng Swift ay sumusuporta sa associated types at generic constraints, na nagbibigay ng flexibility sa pagdisenyo ng mga estratehiya. Ang konteksto ay karaniwang isang ViewModel na klase o serbisyo na tumatanggap ng estratehiya sa init o sa pamamagitan ng isang property. Ang pattern ay malawakang ginagamit sa mga proyekto ng iOS para sa paghawak ng kaganapan, animation, pag-format ng data, at mga estratehiya ng UI.

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

// 2. Mga Konkretong Estratehiya
struct CardPaymentStrategy: PaymentStrategy {
    let cardNumber: String
    let cvv: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Pagpapadala ng kahilingan sa API ng bangko
        return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
    }
}

struct PayPalPaymentStrategy: PaymentStrategy {
    let email: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Pag-redirect sa 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)
    }
}

// Paggamit
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)

Strategy sa SwiftUI — ang pattern ay natural na nagsasama sa MVVM. Ang ViewModel ay naglalaman ng isang property ng estratehiya at tumatawag sa pamamaraan nito sa pagkilos ng gumagamit. Ang SwiftUI View ay tumatanggap ng data sa pamamagitan ng @Published o @State — itinatago ng estratehiya ang mga detalye ng pagpapatupad mula sa View. Halimbawa, ang estratehiya ng pag-validate ng teksto (emailValidator, phoneValidator) ay binabago depende sa uri ng input field. Ang pagsasama ng Strategy sa SwiftUI ay nagbibigay ng flexibility nang walang pamana mula sa UIKit.

Strategy sa Android: pagpapatupad sa Kotlin gamit ang Interface

Strategy sa Kotlin ay gumagamit ng Interface sa antas ng wika at mga functional na interface (SAM) para sa pagpapasimple. Ang Kotlin ay sumusuporta sa lambda, na nagpapahintulot sa pagpasa ng mga algorithm bilang mga function nang hindi nagdedeklara ng isang hiwalay na klase ng estratehiya. Sa Android ang pattern ay inilalapat sa ViewModel at Use Cases para sa paghihiwalay ng mga algorithm ng pag-load ng data, caching, at paghawak ng error. Ang mga proyekto ng Android na may Clean Architecture ay gumagamit ng Strategy para sa pag-inject ng iba't ibang pagpapatupad ng repository batay sa mga flag (mock, real, cache).

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

// 2. Mga Konkretong Estratehiya
class CardPaymentStrategy(
    private val cardNumber: String,
    private val cvv: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // API ng bangko sa pamamagitan ng 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 integration
        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)
    }
}

// Paggamit sa ViewModel
class CheckoutViewModel : ViewModel() {
    private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))

    fun payWithCard() {
        viewModelScope.launch {
            val result = processor.processPayment(BigDecimal("99.99"))
            // Pagproseso ng resulta
        }
    }
}

Strategy gamit ang Hilt/Dagger — sa mga proyekto ng Android, ang mga estratehiya ay madalas na ini-inject sa pamamagitan ng DI. Ang Hilt ay nagbibigay ng konkretong pagpapatupad ng PaymentStrategy sa pamamagitan ng @Binds o @Provides. Ito ay nagpapahintulot sa pagbabago ng estratehiya nang hindi binabago ang code ng konteksto — sapat na upang baguhin ang DI module para sa ibang build (debug/release). Halimbawa, para sa pag-debug ay ini-inject ang MockPaymentStrategy, para sa produksyon — ang tunay na estratehiya ng bangko. Ang kumbinasyon ng Strategy + DI ay nagbibigay ng maximum na flexibility.

Paghahambing ng Strategy sa State, Command at Template Method

Strategy vs State — sa istruktura ang mga pattern ay magkapareho: parehong gumagamit ng komposisyon na may interface at mga konkretong klase. Ang pagkakaiba ay nasa layunin: Strategy ay pumipili ng isang malayang algorithm, State ay namamahala ng pag-uugali ng bagay batay sa estado nito. Sa State ang konteksto mismo ang nagbabago ng estratehiya sa pagbabago ng estado, sa Strategy ang konteksto ay hindi kumokontrol ng paglipat — ang client ay tahasang tumutukoy ng algorithm. Ang mga estratehiya ay hindi alam ang isa't isa, ang mga estado ay maaaring maglipatan.

Strategy vs Command — Command ay nagne-encapsulate ng isang aksyon bilang isang bagay, Strategy ay nagne-encapsulate ng isang set ng mga mapagpapalit na algorithm. Command — «ano ang gagawin» (isang tawag sa execute), Strategy — «paano gagawin» (algorithm ng ilang hakbang). Ang Command ay ginagamit para sa mga pila, naantalang pagpapatupad, undo/redo. Strategy — para sa pagpili ng paraan ng pagpapatupad ng gawain sa runtime. Ang mga command ay maaaring i-parametrize ng mga estratehiya, na pinagsasama ang parehong pattern.

KatangianStrategyStateCommandTemplate Method
LayuninMga mapagpapalit na algorithmPag-uugali batay sa estadoEncapsulation ng kahilinganBalangkas ng algorithm
PagbabagoTahasang ng clientAwtomatiko ng kontekstoNg client o pilaSa pamamagitan ng pamana
AntasBagay (komposisyon)Bagay (komposisyon)BagayKlase (pamana)

Strategy vs Template Method — parehong pattern ay tumutukoy ng mga algorithm, ngunit sa magkaibang paraan. Ang Template Method ay gumagamit ng pamana: ang base class ay tumutukoy ng balangkas ng algorithm (template method), ang mga subclass ay nag-o-override ng mga indibidwal na hakbang. Ang Strategy ay gumagamit ng komposisyon: ang algorithm ay ganap na inilipat sa isang hiwalay na klase. Ang Template Method ay mas simple para sa mga kaso na may nakapirming istraktura ng algorithm, Strategy — kapag ang mga algorithm ay ganap na naiiba at maaaring magbago nang dinamiko.

Mga tunay na halimbawa ng paggamit ng pattern ng Strategy

Pagproseso ng pagbabayad — ang klasikong halimbawa ng Strategy. Ang shopping cart ng isang online na tindahan ay naglalaman ng listahan ng mga produkto, at ang paraan ng pagbabayad ay pinili ng gumagamit. Ang bawat paraan (card, PayPal, Apple Pay, Google Pay, cryptocurrency) — isang hiwalay na estratehiya na may karaniwang lagda na pay(amount). Ang konteksto ng PaymentProcessor ay hindi alam kung paano eksaktong isinasagawa ang pagbabayad — tinatawag nito ang karaniwang pamamaraan. Ang pagdaragdag ng bagong paraan ng pagbabayad ay hindi nangangailangan ng pagbabago ng code ng cart.

Pag-validate ng data — Ang Strategy ay inilalapat para sa iba't ibang mga patakaran ng pag-validate ng parehong field. Ang EmailValidatorStrategy, PhoneValidatorStrategy, AgeValidatorStrategy ay nagpapatupad ng karaniwang interface ng ValidationStrategy na may pamamaraang validate(input). Ang form ng pagpaparehistro ay gumagamit ng isang set ng mga estratehiya para suriin ang bawat field. Ang mga estratehiya ng pag-validate ay maaaring pagsamahin sa isang chain (Chain of Responsibility) o ilapat lahat nang sabay sa isang loop. Pinapalitan nito ang mahahabang pagsusuri ng if-else ng isang koleksyon ng mga polymorphic validator.

swift
// Estratehiya ng pag-uuri
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) }
}

Pagpapatotoo — sa mga mobile application, ang mga estratehiya ng pagpapatotoo ay nagbabago depende sa provider. Ang AuthStrategy na may mga pamamaraang login(), logout(), getToken() ay ipinapatupad para sa EmailPasswordAuth, GoogleAuth, AppleAuth, BiometricAuth. Ang konteksto ng AuthManager ay tumatanggap ng estratehiya sa pamamagitan ng DI o factory. Ito ay nagpapahintulot sa pagdaragdag ng mga bagong provider ng pagpapatotoo nang hindi binabago ang screen ng pag-login. Ang pattern ng Strategy — pundasyon para sa maraming OAuth library at Firebase Authentication.

Mga Madalas Itanong

Kailan gagamitin ang Strategy sa halip na if-else?

Ang Strategy ay makatwiran kapag mayroon kang 3+ algorithm na maaaring magbago o lumawak. Kung 2 ang algorithm at stable ang mga ito — ang simpleng if-else ay hindi gaanong magastos. Gamitin ang Strategy kapag ang mga algorithm ay ginagamit sa iba't ibang bahagi ng application, kapag kailangang palitan ang mga algorithm sa runtime, o kapag ang bawat algorithm ay nangangailangan ng sarili nitong mga dependency at pagsubok.

Ang Strategy ba ay pareho sa State?

Hindi, ito ay magkaibang pattern na may magkatulad na istraktura. Strategy — tahasang pinipili ng client ang algorithm, at ang mga estratehiya ay independyente. State — ang bagay mismo ang nagbabago ng pag-uugali nito sa pagbabago ng panloob na estado, at ang mga estado ay maaaring maglipatan. Sa State ang konteksto ay namamahala ng pagbabago ng estado, sa Strategy — ang client code.

Maaari bang gamitin ang Strategy nang walang mga klase — sa pamamagitan ng closures?

Oo, sa Swift at Kotlin ang estratehiya ay maaaring ipasa bilang isang closure o lambda. Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult. Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult. Pinapasimple nito ang code para sa mga simpleng kaso, ngunit nawawala ang pagpapangalan at dokumentasyon. Para sa 1-2 algorithm — sapat na ang closure, para sa 4+ — mas mahusay ang hiwalay na mga klase.

Paano subukan ang pattern ng Strategy?

Ang bawat estratehiya ay sinusubok ng isang hiwalay na unit test na may mga mock dependency. Ang konteksto ay sinusubok gamit ang isang mock na estratehiya — sinusuri na ang konteksto ay tumatawag sa pamamaraan ng estratehiya at nagpapasa ng tamang mga parameter. Sa Swift gamitin ang XCTest + mga protocol para sa mock, sa Kotlin — MockK o Mockito. Ang pangunahing bentahe: ang bawat estratehiya ay sinusubok nang hiwalay nang walang kumplikadong configuration.

Ang Strategy ba ay isang pattern ng GoF?

Oo, ang Strategy (Estratehiya) — isa sa 23 pattern na inilarawan sa aklat na «Design Patterns: Elements of Reusable Object-Oriented Software» (Gamma, Helm, Johnson, Vlissides, 1994). Ito ay kabilang sa grupo ng mga pattern ng pag-uugali (Behavioral Patterns). Mga kasingkahulugan: Policy (Patakaran). Ang orihinal na halimbawa ng code sa Smalltalk-80 ay makukuha sa orihinal na edisyon ng GoF.

Buod

  • Strategy — pattern ng pag-uugali para sa mga mapagpapalit na algorithm na may karaniwang interface
  • Encapsulation — bawat algorithm ay nakahiwalay sa isang hiwalay na klase ng estratehiya
  • iOS Swift — pagpapatupad sa pamamagitan ng Protocol, mga istraktura at closures
  • Android Kotlin — pagpapatupad sa pamamagitan ng Interface, lambda at DI gamit ang Hilt
  • Prinsipyo ng Open/Closed — ang mga bagong estratehiya ay idinaragdag nang hindi binabago ang konteksto
  • Aplikasyon — pagbabayad, pag-validate, pag-uuri, pagpapatotoo, pag-format

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din