Young Devs Bin
๐Ÿงฉ Design Pattern

Strategy Pattern: Swapping Algorithms Without Touching the Caller

ยท2 min readยท#design-pattern#strategy#kotlin#android#ood

Prepping for a technical interview by designing a ride cost estimation system. The problem: base fare, premium fare, surge pricing โ€” all calculating cost differently but accepting the same input. Classic Strategy territory.

  • When the goal is fixed but the algorithm changes, reach for Strategy โ€” it replaces a long if/else chain with a family of interchangeable classes that all implement the same interface
  • The interface has one job: declare what a strategy does, not how โ€” every concrete strategy fills in the how independently
interface CostStrategy {
    fun calculate(trip: Trip): Double
}
 
class BaseFareStrategy : CostStrategy {
    override fun calculate(trip: Trip): Double {
        return 2.0 + (trip.distance * 1.5) + (trip.duration * 0.25)
    }
}
 
class PremiumStrategy : CostStrategy {
    override fun calculate(trip: Trip): Double {
        return BaseFareStrategy().calculate(trip) * 1.5
    }
}
  • Adding a Decorator on top of Strategy is where things get interesting โ€” SurgePricingStrategy wraps any existing strategy and multiplies the result, so surge can stack on top of base or premium without either one knowing
class SurgePricingStrategy(
    private val wrapped: CostStrategy,
    private val multiplier: Double
) : CostStrategy {
    override fun calculate(trip: Trip): Double {
        return wrapped.calculate(trip) * multiplier
    }
}
  • The Builder pattern solves the "multiple surges at once" problem cleanly โ€” instead of nesting constructors manually, chain the conditions and let build() return the composed strategy
class SurgeStrategyBuilder(private var strategy: CostStrategy) {
    fun applyPeakHour(isPeakHour: Boolean): SurgeStrategyBuilder {
        if (isPeakHour) strategy = SurgePricingStrategy(strategy, 1.5)
        return this
    }
    fun applyHeavyWeather(isHeavyWeather: Boolean): SurgeStrategyBuilder {
        if (isHeavyWeather) strategy = SurgePricingStrategy(strategy, 2.0)
        return this
    }
    fun build(): CostStrategy = strategy
}
  • Open/Closed Principle shows up here without trying โ€” adding a new pricing model means writing a new class, not editing the ones that already work
  • Strategy, Decorator, Builder, and Factory all played a role in one problem; they're not alternatives, they're layers that each solve a different dimension of the same design