Java > Design Patterns in Java > Behavioral Patterns > Strategy Pattern
Strategy Pattern: File Compression
This example demonstrates the Strategy pattern by implementing different file compression algorithms. We define a `CompressionStrategy` interface and concrete implementations for different compression algorithms (Zip, Gzip). The `Compressor` class uses a `CompressionStrategy` to compress a file, allowing you to switch compression algorithms at runtime.
The Core Idea: Strategy Pattern
The Strategy pattern allows you to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. This promotes flexibility and avoids using conditional statements (if/else or switch) to select algorithms at runtime. Instead, you can inject or change the algorithm the client uses.
CompressionStrategy Interface
This interface defines the contract for all concrete compression strategies. All compression algorithms must implement this interface and provide their own `compressFile` method.
interface CompressionStrategy {
void compressFile(String inputFile, String outputFile);
}
Concrete Strategy: Zip Compression
This class implements the `CompressionStrategy` interface using the Zip compression algorithm. It takes an input file, compresses it using Zip, and saves it to the specified output file. It uses standard Java IO and Zip libraries.
import java.io.*;
import java.util.zip.*;
class ZipCompression implements CompressionStrategy {
@Override
public void compressFile(String inputFile, String outputFile) {
try (FileOutputStream fos = new FileOutputStream(outputFile);
ZipOutputStream zipOut = new ZipOutputStream(fos);
FileInputStream fis = new FileInputStream(inputFile)) {
ZipEntry zipEntry = new ZipEntry(new File(inputFile).getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Concrete Strategy: Gzip Compression
This class implements the `CompressionStrategy` interface using the Gzip compression algorithm. It also uses standard Java IO and Gzip libraries to compress the input file.
import java.io.*;
import java.util.zip.*;
class GzipCompression implements CompressionStrategy {
@Override
public void compressFile(String inputFile, String outputFile) {
try (FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
GZIPOutputStream gzipOut = new GZIPOutputStream(fos)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
gzipOut.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Context: Compressor Class
The `Compressor` class is the context. It holds a reference to a `CompressionStrategy` and uses it to perform the compression. The `setCompressionStrategy` method allows you to change the compression algorithm at runtime.
class Compressor {
private CompressionStrategy strategy;
public Compressor(CompressionStrategy strategy) {
this.strategy = strategy;
}
public void setCompressionStrategy(CompressionStrategy strategy) {
this.strategy = strategy;
}
public void compress(String inputFile, String outputFile) {
strategy.compressFile(inputFile, outputFile);
}
}
Client Code
This is the client code that uses the `Compressor` class with different strategies. It first creates a `Compressor` with `ZipCompression` and compresses the file. Then, it changes the strategy to `GzipCompression` and compresses the file again. It also creates a test file.
public class StrategyPatternCompressionExample {
public static void main(String[] args) {
String inputFile = "test.txt"; // Replace with your file
String zipOutputFile = "test.zip";
String gzipOutputFile = "test.gz";
// Create a dummy test file
try (PrintWriter writer = new PrintWriter(inputFile)) {
writer.println("This is a test file for compression.");
writer.println("It contains some sample text.");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Using Zip Compression
Compressor compressor = new Compressor(new ZipCompression());
compressor.compress(inputFile, zipOutputFile);
System.out.println("Compressed to " + zipOutputFile + " using Zip.");
// Using Gzip Compression
compressor.setCompressionStrategy(new GzipCompression());
compressor.compress(inputFile, gzipOutputFile);
System.out.println("Compressed to " + gzipOutputFile + " using Gzip.");
}
}
Real-Life Use Case
Consider a data backup system. You might offer different compression methods to users based on their storage needs and desired compression ratio. The Strategy pattern allows you to easily add and switch between compression algorithms.
Best Practices
Interview Tip
Be prepared to discuss how the Strategy pattern promotes loose coupling and how it aligns with the Open/Closed Principle.
When to Use the Strategy Pattern
Use the Strategy pattern when:
Memory Footprint
The memory footprint of the Strategy pattern in this context is primarily determined by the size of the input file and the internal buffers used by the compression algorithms. The overhead of the strategy objects themselves is relatively small.
Alternatives
Alternatives to the Strategy pattern include:
Pros
Cons
FAQ
-
Can I use the Strategy pattern with other design patterns?
Yes, the Strategy pattern can be combined with other patterns like Factory, Decorator, or Observer to create more complex and flexible solutions. -
How do I choose the right strategy at runtime?
The choice of strategy depends on your application's requirements. You can use configuration files, user input, or other criteria to determine the appropriate strategy.