Implementing the Strategy Pattern in Java for Custom Excel Generation

Core Components of the Strategy Pattern

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Its standard implementation includes three key elements:

  • Context Class (Context): Holds a rfeerence to a strategy object, often delegating the algorithm's execution to it.
  • Strategy Interface (Strategy): A common interface that all concrete algorithm implementations must adhere to.
  • Concrete Strategy Classes: Individual classes that implement the Strategy interface, each providing a specific variant of the algorithm.

Benefits and Drawbacks

Primary Advantages:

  • Enhanced Extensibility: Introducing a new algorithm requires only adding a new concrete strategy class without modifying existing code.
  • Separation of Concerns: Each algorithm is isolated within its own class, promoting single responsibility and simplifying maintenance.

Potential Limitations:

  • Class Proliferation: The number of classes can increase significantly when a large number of strategies are required.

Practical Application: Generating Carrier-Specific Excel Files

Consider a scenario where a system must generate Excel reports tailored for three different telecom carriers (e.g., CarrierA, CarrierB, CarrierC). The content and format of these reports vary per carrier.

Project Structure

src/main/java/com/example/report/
├── controller/
│   └── ReportController.java
├── service/
│   ├── ReportService.java
│   └── impl/
│       └── ReportServiceImpl.java
└── strategy/
    ├── ExcelGenerator.java          // Strategy Interface
    ├── ReportGeneratorContext.java  // Context
    └── impl/
        ├── CarrierAExcelGenerator.java
        ├── CarrierBExcelGenerator.java
        └── CarrierCExcelGenerator.java

Strategy Interface (ExcelGenerator)

Defines the contract for all Excel generation algorithms.

public interface ExcelGenerator {
    Workbook generateWorkbook(String dataSourceId) throws BusinessException;
}

Context Class (ReportGeneratorContext)

Manages the available strategies. It uses Spring's dependency injection to automatically collect all beans implementing ExcelGenerator, keyed by their Spring bean names.

@Component
public class ReportGeneratorContext {
    private final Map<String, ExcelGenerator> generatorRegistry = new ConcurrentHashMap<>();

    @Autowired
    public ReportGeneratorContext(Map<String, ExcelGenerator> strategies) {
        // Strategies map key is the Spring bean name (e.g., "carrierAExcelGenerator")
        this.generatorRegistry.putAll(strategies);
    }

    public Workbook executeGeneration(String carrierCode, String dataSourceId) throws BusinessException {
        ExcelGenerator selectedGenerator = generatorRegistry.get(carrierCode);
        if (selectedGenerator == null) {
            throw new BusinessException("ERR_CARRIER_NOT_SUPPORTED", "Unsupported carrier code: " + carrierCode);
        }
        return selectedGenerator.generateWorkbook(dataSourceId);
    }
}

Concrete Strategy Implementations

Each class implements the generation logic for a specific carrier.

Example for Carrier A:

@Service("carrierA") // Bean name acts as the strategy key
public class CarrierAExcelGenerator implements ExcelGenerator {
    private static final Logger log = LoggerFactory.getLogger(CarrierAExcelGenerator.class);

    @Override
    public Workbook generateWorkbook(String dataSourceId) throws BusinessException {
        log.info("Generating Carrier A report for ID: {}", dataSourceId);
        // Specific logic to create Carrier A's Excel format
        Workbook wb = new XSSFWorkbook();
        // ... populate sheets, rows, cells for Carrier A ...
        return wb;
    }
}

Examples for Carrier B and Carrier C would follow the same pattern, with unique bean names (e.g., "carrierB", "carrierC") and their own internal logic.

Service Layer Integration (ReportServiceImpl)

The service orchestrates the generation process by utilizing the context.

@Service
public class ReportServiceImpl implements ReportService {
    private static final Logger log = LoggerFactory.getLogger(ReportServiceImpl.class);

    @Autowired
    private ReportGeneratorContext reportContext;

    @Override
    public void exportReports(String dataSourceId, HttpServletResponse servletResponse) throws BusinessException {
        try {
            // Delegate generation to the appropriate strategies via the context
            Workbook reportForA = reportContext.executeGeneration("carrierA", dataSourceId);
            Workbook reportForB = reportContext.executeGeneration("carrierB", dataSourceId);
            Workbook reportForC = reportContext.executeGeneration("carrierC", dataSourceId);

            // Subsequent logic: write workbooks to response, combine files, etc.
            // ...
        } catch (BusinessException ex) {
            log.error("Report generation failed", ex);
            throw ex;
        }
    }
}

Controller Endpoint (ReportController)

A REST controller exposes the functionality.

@RestController
@RequestMapping("/api/reports")
public class ReportController {
    private static final Logger log = LoggerFactory.getLogger(ReportController.class);

    @Autowired
    private ReportService reportService;

    @PostMapping("/export")
    public ResponseEntity<?> triggerExport(@RequestParam("sourceId") String sourceId,
                                           HttpServletRequest request,
                                           HttpServletResponse response) {
        try {
            log.info("Export request for source: {}", sourceId);
            reportService.exportReports(sourceId, response);
            return ResponseEntity.ok().build();
        } catch (BusinessException e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ErrorResponse(e.getCode(), e.getMessage()));
        }
    }
}

This approach cleanly separates the varying Excel generation logic for each carrier into distinct strategy classes. The ReportGeneratorContext serves as a central dispatcher, selecting and executing the correct strategy based on a simple identifier. New carriers can be supported by adding a new implementation of ExcelGenerator without altering the existing service or context code.

Tags: java Design Patterns Strategy Pattern Spring Framework Software Architecture

Posted on Sat, 29 Aug 2026 16:43:24 +0000 by cloudzilla