سؤال

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:

  1. I'm having to reset the strategy each time
  2. The Two strategies may or may not be compatible (in that order, e.g. does it make sense to Tar a GZipped file?)
  3. Creating a third TARGZipStrategy class is ok in principle, but if we had 10 strategies allowing for every other one to be part of a valid XXXCombinedStrategy method, we'd have ~35 different classes.

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.

هل كانت مفيدة؟

المحلول

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);
public class TgzCompressionStrategy implements CompressionStrategy
{
     TarCompressionStrategy tar = new TarCompressionStrategy();
     ZipCompressionStrategy zip = new ZipCompressionStrategy();

    public File compressFiles(ArrayList<File> files)
    {
        File archive = tar.compressFiles(files);
        archive = zip.compressFiles(archive); // need to handle archive is not array list, but you can do that
        return archive;
    }

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top