Java 从库中分离客户端代码

Java 从库中分离客户端代码,java,refactoring,decoupling,Java,Refactoring,Decoupling,我们有一个与Sanselan库紧密耦合的图像实用程序方法,现在我需要添加第二个库(元数据提取器),以尝试读取图像的元信息,以防Sanselan无法做到这一点 我说,我们的代码与Sanselan紧密耦合,因为我们有几个直接调用Sanselan的静态方法,或者调用其中一个方法返回的对象的getter(用//Sanselan注释的行) 我的方法是创建一个对象,该对象提供与我们当前调用的方法相同的方法(getHeight,getWidth,getColorType,getIccProfile,getFo

我们有一个与Sanselan库紧密耦合的图像实用程序方法,现在我需要添加第二个库(元数据提取器),以尝试读取图像的元信息,以防Sanselan无法做到这一点

我说,我们的代码与Sanselan紧密耦合,因为我们有几个直接调用Sanselan的静态方法,或者调用其中一个方法返回的对象的getter(用//Sanselan注释的行)

我的方法是创建一个对象,该对象提供与我们当前调用的方法相同的方法(
getHeight
getWidth
getColorType
getIccProfile
getFormat
)。我将把
字节[]
传递给对象构造函数,并定义两个策略(不确定是否应该调用它们)。主要策略是尝试使用梵语阅读图像。如果抛出异常,故障转移策略将尝试使用新库元数据提取器读取映像

public class ImageMetaInfo
{

    public static final String IMAGE_FORMAT_JPEG = "JPEG";

    private static Log LOGGER = LogFactory.getLog(ImageValidator.class);

    private final int width;
    private final int height;
    private final String format;
    private final int colorType;
    private final ICC_Profile icc_profile;

    public ImageMetaInfo(byte[] image) throws Exception
    {
        ImageMetaInfoWrapper wrapper;
        try
        {
            wrapper = new SanselanImageMetaInfoWrapper();
        }
        catch (ImageReadException | IOException e)
        {
            LOGGER.error("Image could not be read with Sanselan, trying Metadata Extractor");
            try
            {
                wrapper = new MetadataExtractorMetaInfoWrapper();
            }
            catch (ImageProcessingException | IOException | MetadataException e1)
            {
                LOGGER.error("Also failed to read the image using Metadata Extractor", e1);
                throw new Exception("Couldn't create instance from the given data", e1);
            }
        }

        this.width = wrapper.getWidth();
        this.height = wrapper.getHeight();
        this.format = wrapper.getFormat();
        this.icc_profile = wrapper.getICCProfile();
        this.colorType = wrapper.getColorType();
    }

    public int getWidth()
    {
        return width;
    }

    public int getHeight()
    {
        return height;
    }

    public Object getFormat()
    {
        return format;
    }

    public int getColorType()
    {
        return colorType;
    }

    public ICC_Profile getICCProfile()
    {
        return icc_profile;
    }

}
然后,在
ImageMetaInfoWrapper
的每个实现中,使用相应的库解析图像。 我的问题是这看起来太复杂了。我在另一个包装器(
ImageMetaInfoWrapper
)中有一个包装器(
ImageMetaInfoWrapper

  • 是否有更好/更干净的方法,将对现有代码的更改保持在最低限度
  • 是否可以/应该在此处使用

  • 我想在代码评审中发布这个问题,但我认为我的问题在更高的层次上,更多地是关于编码的设计。

    另一个选择是使用模板方法模式。将与Sanselan或alternative相关的功能推送到子类中

    如果您的实用程序方法是其类的主要用途,那么您可以为不同的库创建它的子类。 如果这是一个次要的问题,您可能会希望首先提取方法对象

    当然,您最终也可能需要一个工厂来为您提供正确的子类

    BufferedImage toBufferedImageJpeg2(byte[] image) throws Exception
        {
            ImageMetaInfo imageInfo = new ImageMetaInfo(image);
            if (isImageTooBig(imageInfo.getHeight(), imageInfo.getWidth())) // Sanselan
            {
                throw new IllegalArgumentException("Image is too big");
            }
            if (imageInfo.getFormat().equals(ImageFormat.IMAGE_FORMAT_JPEG)) // Sanselan
            {
                if (ImageInfo.COLOR_TYPE_CMYK == imageInfo.getColorType()) // Sanselan
                {
                    ICC_Profile iccProfile = imageInfo.getICCProfile(); // Sanselan
                    ImageInputStream imageInputStream = ImageIO.createImageInputStream(new ByteArrayInputStream(image));
    
    public class ImageMetaInfo
    {
    
        public static final String IMAGE_FORMAT_JPEG = "JPEG";
    
        private static Log LOGGER = LogFactory.getLog(ImageValidator.class);
    
        private final int width;
        private final int height;
        private final String format;
        private final int colorType;
        private final ICC_Profile icc_profile;
    
        public ImageMetaInfo(byte[] image) throws Exception
        {
            ImageMetaInfoWrapper wrapper;
            try
            {
                wrapper = new SanselanImageMetaInfoWrapper();
            }
            catch (ImageReadException | IOException e)
            {
                LOGGER.error("Image could not be read with Sanselan, trying Metadata Extractor");
                try
                {
                    wrapper = new MetadataExtractorMetaInfoWrapper();
                }
                catch (ImageProcessingException | IOException | MetadataException e1)
                {
                    LOGGER.error("Also failed to read the image using Metadata Extractor", e1);
                    throw new Exception("Couldn't create instance from the given data", e1);
                }
            }
    
            this.width = wrapper.getWidth();
            this.height = wrapper.getHeight();
            this.format = wrapper.getFormat();
            this.icc_profile = wrapper.getICCProfile();
            this.colorType = wrapper.getColorType();
        }
    
        public int getWidth()
        {
            return width;
        }
    
        public int getHeight()
        {
            return height;
        }
    
        public Object getFormat()
        {
            return format;
        }
    
        public int getColorType()
        {
            return colorType;
        }
    
        public ICC_Profile getICCProfile()
        {
            return icc_profile;
        }
    
    }