Examples below are shamelessly ripped off of java.dzone.com, and modified to suit my needs:
Our interface:
public interface CompressionStrategy
{
public void compressFiles(ArrayList<File> files);
}
Our First Implementation
public class GZipCompressionStrategy implements CompressionStrategy
{
public File compressFiles(ArrayList<File> files)
{
//using GZIP approach
return archive;
}
}
Our Second Implementation:
public class TarCompressionStrategy implements CompressionStrategy
{
public File compressFiles(ArrayList<File> files)
{
//using TAR approach
return archive;
}
}
And this is the use given:
public class CompressionContext
{
private CompressionStrategy strategy;
//this can be set at runtime by the application preferences
public void setCompressionStrategy(CompressionStrategy strategy)
{
this.strategy = strategy;
}
//use the strategy
public File createArchive(ArrayList<File> files)
{
strategy.compressFiles(files);
}
}
Client Class with Main method
public class Client
{
public static void main(String[] args)
{
CompressionContext ctx = new CompressionContext();
File archive;
//we could assume context is already set by preferences
ctx.setCompressionStrategy(new TarCompressionStrategy());
//get a list of files
...
archive = ctx.createArchive(fileList);
ctx. setCompressionStrategy(new GZipCompressionStrategy());
archive = ctx.createArchive(archive);
}
}
Which feels messy, because:
Is there a neat way to arbitrarily run multiple strategies sequentially within this pattern? For instance if I wanted to create a .tar.gzip
file at the end?
What I'm trying to say is there neat way to combine two strategies together into one?
I feel like what I'm doing should have some neat solution and I don't want to reinvent the wheel, and at the same time I don't want to fall into being too reliant on patterns.
No you can have more than one method on your strategy interface. However, in order for your strategy object to actually use the Strategy pattern, at least one of the method implementations should differ between the different strategies.
Yes, a combination of the Comparator, Comparable, and the Collections. sort() method is one of the best real-world examples of the Strategy design pattern.
State pattern helps a class to exhibit different behaviors in a different state. Strategy Pattern encapsulates a set of related algorithms and allows the client to use interchangeable behaviors through composition and delegation at runtime.
Strategy design pattern is one of the behavioral design pattern. Strategy pattern is used when we have multiple algorithm for a specific task and client decides the actual implementation to be used at runtime.
You could create a JoinedCompressionStrategy
class JoinedCompressionStrategy implements CompressionStrategy {
private final CompressionStrategy s0;
private final CompressionStrategy s1;
public JoinedCompressionStrategy(CompressionStrategy s0, CompressionStrategy s1) {
this.s0 = s0;
this.s1 = s1;
}
public File compressFiles(ArrayList<File> files) {
File archive = s0.compressFiles(files);
return s1.compressFiles(Arrays.asList(archive));
}
}
You probably are looking for a decorator pattern implementation instead. The intent of this pattern is to add additional responsibilities dynamically to an object. Tradeoff is that you'll get a explossion of subclasses too.
Example with code:
The common interface.
public interface CompressionStrategy{
File compressFiles(List<File> files);
}
the base compression for all files.
public class CompressionBase implements CompressionStrategy{
@Override
public File compressFiles(List<File> files)) {
//return default compression
}
}
The decorator abstract class
public abstract class AbstractCompressionDecorator implements CompressionStrategy{
private final CompressionStrategy decoratee;
/**
* @param decoratee
*/
public AbstractCompressionDecorator(CompressionStrategy decoratee) {
super();
this.decoratee = decoratee;
}
@Override
public File compressFiles(List<File> files) {
File file = decoratee.compressFiles(files);
return compressFilesToAnotherFormat(file);
}
protected abstract File compressFilesToAnotherFormat(File file);
}
and the decorators concrete classes.
public class TarCompression extends AbstractCompressionDecorator {
public TarCompression (CompressionStrategy compressionStrategy) {
super(compressionStrategy);
}
@Override
protected File compressFilesToAnotherFormat(File file) {
// tar compression logic here;
}
}
Zip compression
public class ZipCompression extends AbstractCompressionDecorator {
public ZipCompression (CompressionStrategy compressionStrategy) {
super(compressionStrategy);
}
@Override
protected File compressFilesToAnotherFormat(File file) {
// zip compression logic here;
}
and a simple Factory to create objects
public final class CompressionFactory {
private CompressionFactory (){}
public static CompressionStrategy create(String extension){
CompressionStrategy compressionStrategy = new CompressionBase();
if(extension.contains("zip")){
compressionStrategy = new ZipCompression(compressionStrategy);
}else if(extension.contains("tar.gzip")){
compressionStrategy = new TarCompression(new GzipCompression(compressionStrategy));
}
return compressionStrategy ;
}
}
then in client code you only have to write this.
CompressionStrategy compressionStrategy = CompressionFactory.create("tar.gzip");
File file = compressionStrategy.compressFiles(files);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With