I'm a developing a image processor, which reads a Base64 (compressed) image and writes its subimage to target
s on threads.
(Constructors, exception handling, and resource management are omitted for brevity)
The base abstract class is AbstractImageProcessor
and it implements Runnable
to run on threads:
abstract class AbstractImageProcessor implements Runnable {
protected final String base64; // input
protected final List<Target> targetList; // list of target information
protected abstract void read(byte[] data);
protected abstract void write(Target t);
@Override
public void run() {
byte[] data = decompress(decode()); // decode base64 and decompress
read(data);
for (Target t : targetList) {
write(t)
}
}
}
Another abstract class, ImageIOProcessor
extends AbstractImageProcessor
to use ImageIO
:
abstract class ImageIOProcessor extends AbstractImageProcessor {
private BufferedImage image;
protected abstract void writeBufferedImage(BufferedImage subimage, Target t)
@Override
protected void read(byte[] data) {
image = ImageIO.read(new ByteArrayInputStream(data));
}
@Override
protected void write(Target t) {
writeBufferedImage(image.getSubimage(/* x, y, w, h from t */), t);
}
}
There are two default implementations(concrete classes) of ImageIOProcessor
, one writes to file and the other writes to base64 String:
class ImageIOFileWriter extends ImageIOProcessor {
private File filepath;
@Override
protected void writeBufferedImage(BufferedImage subimage, Target t) {
ImageIO.write(subimage, "png", filepath);
}
}
class ImageIOBase64Writer extends ImageIOProcessor {
@Override
protected void writeBufferedImage(BufferedImage subimage, Target t) {
ImageIO.write(subimage, "png", /* Base64-encoder-wrapped outputstream*/);
}
}
The factory interface is responsible for creating appropriate image processing Runnable
instance:
public interface ImageProcessorFactory {
AbstractImageProcessor create(String base64, List<Target> t);
}
Is this the best way to implement them? Or is there better design pattern?
public
? What does theTarget
look like? E.g. why is it passed towriteBufferedImage
? Does it provide a file path, or an output stream? Should clients be able to plug in own implementations at some point? What are the intended usage patterns in general? Right now, it looks like you could just let the factory return an anonymous, structure-freeRunnable
object, but I guess that's not the goal... \$\endgroup\$ – Marco13 Apr 3 '18 at 0:38