Total Pageviews

2017/02/04

[Design Pattern] Strategy Pattern

Assume I have a data exporter which can export data to PDF, XLS or HTML format. It can export data to different format depends on your demand.

Firstly, creating a strategy interface:
package albert.practice.designpattern.strategy;

public interface ExportStrategy {

    void exportData(String data);
    
}


Secondly, creating concrete classes implements strategy interface.
package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ExcelExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into excel file.");
    }

}



package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HtmlExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into html file.");
    }

}



package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class PdfExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into pdf file.");
    }

}


The DataExport class will export data depends on client's demands.

package albert.practice.designpattern.strategy;

public class DataExport {

    public static void main(String[] args) {
        String data = "[test data]";
        
        DataExport exporter = new DataExport();
        exporter.exportData(FileTypeEnum.XLS, data);
        exporter.exportData(FileTypeEnum.PDF, data);
        exporter.exportData(FileTypeEnum.HTML, data);
    }

    public void exportData(FileTypeEnum fileType, String data) {
        ExportStrategy exporter = null;
        if (FileTypeEnum.XLS == fileType) {
            exporter = new ExcelExporter();
        } else if (FileTypeEnum.PDF == fileType) {
            exporter = new PdfExporter();
        } else if (FileTypeEnum.HTML == fileType) {
            exporter = new HtmlExporter();
        }
        exporter.exportData(data);
    }

}




We create objects which represent various export strategies, but we still expose if-else logic in client. Therefore, we create an ExportStrategy class which will change the executing algorithm of the context object (i.e. PdfExporter, HtmlExporter, and ExcelExporter).
package albert.practice.designpattern.strategy;

import lombok.Data;

@Data
public class ExporterContext {
    
    private String data;
    
    public void doExport(ExportStrategy strategy) {
        strategy.exportData(this.data);
    }
    
}



And the DataExport will be modified as bellows:

package albert.practice.designpattern.strategy;

public class DataExport {

    public static void main(String[] args) {
        String data = "[test data]";
        
        ExporterContext context = new ExporterContext();
        context.setData(data);
        context.doExport(new HtmlExporter());
        context.doExport(new ExcelExporter());
        context.doExport(new PdfExporter());
    }

}



To sum up, we create a ExportStrategy interface which define an exportData action and concrete strategy classes (i.e. PdfExporter, ExcelExporter, HtmlExporter) implementing the ExportStrategy interface. ExporterContext is a class which uses a Strategy.
DataExport, our demo class, use Context and strategy objects to demonstrate change in Context behaviour based on strategy  (i.e. PdfExporter, ExcelExporter, HtmlExporter) it uses.


No comments: