Template Design Pattern

Hello reader! I hope you feeling good today because you are gonna learn something pretty cool! Well at least thats how I see it... Right, so I wont go into details explaining in theory what it is I am pretty sure you checked that already and you want to see an implementation around it, right? So, I'm going to walk you through an example from my work.. So I had two selectors from Redux that had same logic and conditions apart from a small part that makes them quite distinguished. Selector A. export const selectSomeSelectorNameForNotDomesticUser = createSelector( selectSomeLocation, selectSomeDestination, selectUserCountry, (originUser, destinationUser, userCountry) => { const userOriginCountryCode = originUser.countryCode; const userDestinationCountryCode = destinationUser.countryCode; if ( userCountry === userOriginCountryCode || userCountry === userDestinationCountryCode ) { return false; } return true; } ); Selector B. export const selectSomeSelectorNameForDomesticUser = createSelector( selectSomeLocation, selectSomeDestination, selectUserCountry, (originUser, destinationUser, userCountry) => { const userOriginCountryCode = originUser.countryCode; const userDestinationCountryCode = destinationUser.countryCode; if ( userCountry === userOriginCountryCode || userCountry === userDestinationCountryCode ) { return true; } return false; } ); So you can see that the skeleton of the selectors and the main logic is the same, however are a bit different in the interpretation. For that I thought it would be a good idea to utilise the Template Method Pattern, also because I was curious about the implementation. So the first thing you do is to create the Abstract class that holds the main functionality and then the sub-class that they have to interpret accordingly that logic. Abstract Component: The abstract class contains the template method and the private methods in common. The abstract class contains the code basically that is duplicated or is common. So here we are using the evaluate method, because we want to focus on performing a specific operation or calculation, in our case to evaluate or determine if a user is domestic or not based on their country/ location. abstract class UserDomesticEvaluator { protected abstract shouldReturn(isMatch: boolean): boolean; public evaluate( originUser: Location | undefined, destinationUser: Location | undefined, userCountry: string | undefined ): boolean { const userOriginCountryCode = originUser.countryCode; const userDestinationCountryCode = destinationUser.countryCode; if (!userCountry || (!originLocation && !destinationLocation)) { return this.shouldReturn(false); } const isMatch = userCountry === userOriginCountryCode || userCountry === userDestinationCountryCode; return this.shouldReturn(isMatch); } } Then the two sub-classes export class IsDomesticUser extends UserDomesticEvaluator { protected shouldReturn(isMatch: boolean): boolean { return isMatch; } } export class IsNotDomesticUser extends UserDomesticEvaluator { protected shouldReturn(isMatch: boolean): boolean { return !isMatch; } } Then in the code where you are using it you can just create a new instance of this class: const isDomesticUser = new IsDomesticUser() isDomesticUser.evaluate(your params here: origin, destination, usercountry) Happy coding!

May 1, 2025 - 11:28
 0
Template Design Pattern

Hello reader!

I hope you feeling good today because you are gonna learn something pretty cool! Well at least thats how I see it...

Right, so I wont go into details explaining in theory what it is I am pretty sure you checked that already and you want to see an implementation around it, right?

So, I'm going to walk you through an example from my work..

So I had two selectors from Redux that had same logic and conditions apart from a small part that makes them quite distinguished.

Selector A.

export const selectSomeSelectorNameForNotDomesticUser = createSelector(
  selectSomeLocation,
  selectSomeDestination,
  selectUserCountry,
  (originUser, destinationUser, userCountry) => {
    const userOriginCountryCode = originUser.countryCode;
    const userDestinationCountryCode = destinationUser.countryCode;

    if (
      userCountry === userOriginCountryCode ||
      userCountry === userDestinationCountryCode
    ) {
      return false;
    }

    return true;
  }
);

Selector B.

export const selectSomeSelectorNameForDomesticUser = createSelector(
  selectSomeLocation,
  selectSomeDestination,
  selectUserCountry,
  (originUser, destinationUser, userCountry) => {
    const userOriginCountryCode = originUser.countryCode;
    const userDestinationCountryCode = destinationUser.countryCode;

    if (
      userCountry === userOriginCountryCode ||
      userCountry === userDestinationCountryCode
    ) {
      return true;
    }

    return false;
  }
);

So you can see that the skeleton of the selectors and the main logic is the same, however are a bit different in the interpretation. For that I thought it would be a good idea to utilise the Template Method Pattern, also because I was curious about the implementation.

So the first thing you do is to create the Abstract class that holds the main functionality and then the sub-class that they have to interpret accordingly that logic.

Abstract Component:

The abstract class contains the template method and the private methods in common. The abstract class contains the code basically that is duplicated or is common.
So here we are using the evaluate method, because we want to focus on performing a specific operation or calculation, in our case to evaluate or determine if a user is domestic or not based on their country/ location.

abstract class UserDomesticEvaluator {
  protected abstract shouldReturn(isMatch: boolean): boolean;

  public evaluate(
    originUser: Location | undefined,
    destinationUser: Location | undefined,
    userCountry: string | undefined
  ): boolean {
    const userOriginCountryCode = originUser.countryCode;
    const userDestinationCountryCode = destinationUser.countryCode;

    if (!userCountry || (!originLocation && !destinationLocation)) {
      return this.shouldReturn(false);
    }

    const isMatch =
      userCountry === userOriginCountryCode ||
      userCountry === userDestinationCountryCode;

    return this.shouldReturn(isMatch);
  }
}

Then the two sub-classes

export class IsDomesticUser extends UserDomesticEvaluator {
  protected shouldReturn(isMatch: boolean): boolean {
    return isMatch;
  }
}

export class IsNotDomesticUser extends UserDomesticEvaluator {
  protected shouldReturn(isMatch: boolean): boolean {
    return !isMatch;
  }
}

Then in the code where you are using it you can just create a new instance of this class:

const isDomesticUser = new IsDomesticUser()

isDomesticUser.evaluate(your params here: origin, destination, usercountry)

Happy coding!