mercredi 22 mars 2023

Template Method vs Decorator Pattern

I write the code in Java and I have a case where I need to get the status of an order depending on the product type. Each product type has the same base logic as written below.

protected String getStatus(ProductType productType, Result result) {
  if (result.isSuccess()) {
    return "SUCCESS";
  } else if (result.getPaymentMethod().equals("TRANSFER")) {
    return "WAITING_CONFIRMATION";
  } else {
    return "WAITING_PAYMENT";
  }
}

However, each product type can have custom logic. For example:

  • if product type is "A", no need to modify the logic above
  • if the status returned from the method above is "SUCCESS" and the product type is "B", I need to call another service to check the status of the product issuance
  • if the status returned from the method above is "SUCCESS" and the product type is "C", I need to call partner service.

My question is what is the best design pattern to implement?

The first idea is using something like template method pattern

public class BaseProductStatusService {

  public String getStatus(Result result, Product product) {
    String status;
    if (result.isSuccess()) {
      status = "SUCCESS";
    } else if (result.getPaymentMethod().equals("TRANSFER")) {
      status = "WAITING_CONFIRMATION";
    } else {
      status = "WAITING_PAYMENT";
    }

    return doGetStatus(status);
  }

  protected String doGetStatus(String status, Product product) {
    return status;
  }
}

// For product A, no need to have its own class since it can use the base class

public class ProductBStatusService extends BaseProductStatusService {

  @Override
  protected String doGetStatus(String status, Product product) {
    if (status.equals("SUCCESS")) {
      return this.checkProductIssuance(product);
    }

    return status;
  }
}

public class ProductCStatusService() extends BaseProductStatusService {

  @Override
  protected String doGetStatus(String status, Product product) {
    if (status.equals("SUCCESS")) {
      return this.checkStatusToPartner(product);
    }

    return status;
  }
}

Another alternative is using decorator pattern

public interface ProductStatusService() {
   String getStatus(Result result, Product product);
}

public class DefaultProductStatusService implements ProductStatusService {

  public String getStatus(Result result, Product product) {
    String status;
    if (result.isSuccess()) {
      status = "SUCCESS";
    } else if (result.getPaymentMethod().equals("TRANSFER")) {
      status = "WAITING_CONFIRMATION";
    } else {
      status = "WAITING_PAYMENT";
    }

    return doGetStatus(status);
  }
}

public abstract class ProductStatusServiceDecorator implements ProductStatusService {

  private ProductStatusService productStatusService;

  public ProductStatusServiceDecorator(ProductStatusService productStatusService) {
    this.productStatusService = productStatusService;
  }

  public String getStatus(Result result, Product product) {
    return this.productStatusService.getStatus();
  }
}

// For product A, no need to have its own class since it can use the DefaultProductStatusService class

public class ProductBStatusServiceDecorator extends ProductStatusServiceDecorator {

  public ProductStatusServiceDecorator(ProductStatusService productStatusService) {
    super(productStatusService);
  }

  public String getStatus(Result result, Product product) {
    String status = super.getStatus();

    if (status.equals("SUCCESS")) {
      return this.checkProductIssuance(product);
    }

    return status;
  }
}

public class ProductCStatusServiceDecorator extends ProductStatusServiceDecorator {

  public ProductStatusServiceDecorator(ProductStatusService productStatusService) {
    super(productStatusService);
  }

  public String getStatus(Result result, Product product) {
    String status = super.getStatus();

    if (status.equals("SUCCESS")) {
      return this.checkStatusToPartner(product);
    }

    return status;
  }
}

which one is better for the above case and what is the reason? or do you have other suggestion?

Aucun commentaire:

Enregistrer un commentaire