Skip to content

Instantly share code, notes, and snippets.

@shershen08
Last active October 19, 2022 17:08
Show Gist options
  • Save shershen08/232f7518daa8142841c31e061ce91f40 to your computer and use it in GitHub Desktop.
Save shershen08/232f7518daa8142841c31e061ce91f40 to your computer and use it in GitHub Desktop.
Strategy and factory patterns in TypeScript
// see article with examples in JAVA here: https://dzone.com/articles/design-patterns-the-strategy-and-factory-patterns
// example for educational purposes shownig close and mature syntax of modern TypeScript
enum AccountTypes {CURRENT, SAVINGS, HIGH_ROLLER_MONEY_MARKET, STANDARD_MONEY_MARKET}
////////////////////////////////////////
/// the interface that is used by the strategy
////////////////////////////////////////
interface InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number;
}
////////////////////////////////////////
/// Null object implementation and 4 account type related calculation stategies
////////////////////////////////////////
class NoInterestCalculation implements InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number {
return 0;
}
}
class CurrentAccountInterestCalculation implements InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number {
return +accountBalance * (0.02 / 12);
}
}
class SavingsAccountInterestCalculation implements InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number {
return +accountBalance * (0.04 / 12);
}
}
class MoneyMarketInterestCalculation implements InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number {
return +accountBalance * (0.06/12);
}
}
class HighRollerMoneyMarketInterestCalculation implements InterestCalculationStrategy {
calculateInterest(accountBalance:Number):Number {
return accountBalance < 100000.00 ? 0 : (+accountBalance) * (0.075/12)
}
}
////////////////////////////////////////
/// select and apply the correct strategy
////////////////////////////////////////
class InterestCalculationStrategyFactory {
//Strategies for calculating interest.
private currentAccountInterestCalculationStrategy:InterestCalculationStrategy = new CurrentAccountInterestCalculation();
private savingsAccountInterestCalculationStrategy:InterestCalculationStrategy = new SavingsAccountInterestCalculation();
private moneyMarketAccountInterestCalculationStrategy:InterestCalculationStrategy = new MoneyMarketInterestCalculation();
private highRollerMoneyMarketAccountInterestCalculationStrategy:InterestCalculationStrategy = new HighRollerMoneyMarketInterestCalculation();
private noInterestCalculationStrategy:InterestCalculationStrategy = new NoInterestCalculation();
public getInterestCalculationStrategy(accountType:AccountTypes):InterestCalculationStrategy {
switch (accountType) {
case AccountTypes.CURRENT: return this.currentAccountInterestCalculationStrategy;
case AccountTypes.SAVINGS: return this.savingsAccountInterestCalculationStrategy;
case AccountTypes.STANDARD_MONEY_MARKET: return this.moneyMarketAccountInterestCalculationStrategy;
case AccountTypes.HIGH_ROLLER_MONEY_MARKET: return this.highRollerMoneyMarketAccountInterestCalculationStrategy;
default: return this.noInterestCalculationStrategy;
}
}
}
@bay007
Copy link

bay007 commented May 19, 2017

I think that using switch is an anti pattern.

@angeliski
Copy link

I think that using switch is an anti pattern(2).

@jhm-ciberman
Copy link

I think that using switch is an anti pattern(3).

@Labrat02
Copy link

Labrat02 commented Feb 7, 2018

I think that using switch is an anti pattern(4).

@m1m1s1ku
Copy link

I think that using switch is an anti pattern(5).

@Marcrobito
Copy link

I think that using switch is an anti pattern ++

@AlcantaraRW
Copy link

What solution would be better to get rid of that switch block?

@bidego
Copy link

bidego commented Dec 28, 2018

getInterestCalc(type) : void {
eval("new InterestStrat"+type+"()");
}
class InteresStratTypeA implements Interface {}
class InteresStratTypeB implements Interface {}

Im working out another solution due to eval deprecation.

@joshrizzo
Copy link

Did you ever figure out a better solution? I tried using an Enum and creating an object mapping each value to functions, but I could not get it to work in TS.

@savalazic
Copy link

@shershen08 @joshrizzo

interface InterestCalculationStrategy {
  calculateInterest(accountBalance:Number):Number;
  test(type: AccountTypes): boolean;
}

// and then you implement test function for every strategy
class SavingsAccountInterestCalculation implements InterestCalculationStrategy {
    test(type: AccountType) {
        return type === AccountType.SAVING
    }
    
    calculateInterest(accountBalance:Number):Number {
        return +accountBalance * (0.04 / 12);
    }
}

class InterestCalculationStrategyFactory {
   strategies = [
     new SavingsAccountInterestCalculation(),
     // ...all other strategies
  ]

  getInterestCalculationStrategy(accountType:AccountTypes):InterestCalculationStrategy {
    return this.strategies.find(strategy => strategy.test(accountType));
  }
}

@dijalmasilva
Copy link

dijalmasilva commented Mar 18, 2021

it could be like that too...

interface InterestCalculationStrategy {
  calculateInterest(accountBalance:Number):Number;
}

// and then you implement test function for every strategy
class SavingsAccountInterestCalculation implements InterestCalculationStrategy {
    calculateInterest(accountBalance:Number):Number {
        return +accountBalance * (0.04 / 12);
    }
}

class InterestCalculationStrategyFactory {
  private static strategies = {
     [AccountTypes.SAVING]: new SavingsAccountInterestCalculation(),
     // ...all other strategies
  }

  static getInterestCalculationStrategy(accountType:AccountTypes):InterestCalculationStrategy {
    return InterestCalculationStrategyFactory.strategies[accountType];
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment