Search code examples
javaoopenumstype-safety

Pattern for storing various types in a field


In a Java class that belongs in a library, I have a field size that indicates size of image. It must be int, but some values are depending to devices, so other developers can set various types for it:

  1. thumbnail (value depends on device)
  2. real size (value depends on device)
  3. custom (arbitrary integer)

I want to restrict other developers (that use this library) to set value of size with one option from set of specific and meaningful options.My purpose is to show list of legal options to developer and also type safety, like Enum. But I think it is impossible to do that only by enum, so I create an interface and some classes:

public interface SizeMode {
}

public enum DevicePreDefinedImageSizeMode implements SizeMode {
    THUMBNAIL, REAL_SIZE
}

public enum CustomImageSizeMode implements SizeMode {
    CUSTOM_SIZE
}

public abstract class Size {

    private final SizeMode mode;

    public SizeMode getMode() {
        return mode;
    }

    public abstract int getDownSampleFactor();

    protected Size(SizeMode mode) {
        this.mode = mode;
    }
}

public class DevicePreDefinedImageSize extends Size {

    public DevicePreDefinedImageSize(DevicePreDefinedImageSizeMode mode) {
        super(mode);
    }

    @Override
    public int getDownSampleFactor() {
        throw new UnknownError("????");
    }

}

public class CustomImageSize extends Size {
    private final int downSampleFactor;

    private CustomImageSize(CustomImageSizeMode mode, int downSampleFactor) {
        super(mode);
        this.downSampleFactor = downSampleFactor;
    }

    @Override
    public int getDownSampleFactor() {
        return downSampleFactor;
    }

}

Now I can declare field size of type Size class and other developers are restricted to use one of sub classes of Size and initialize them with THUMBNAIL, REAL_SIZE or CUSTOM_SIZE.

But is there a better approach to achieve my purpose?


Solution

  • Another option is to use Size implementation that can only be created using set of static factory methods (or Builder pattern if you want):

    public class Size {
        private final int sampleFactor;
    
        private Size(int sampleFactor) {
            this.sampleFactor = sampleFactor;
        }
    
        public static Size thumbnail() {
            return new Size(THUMBNAIL_FACTOR);
        }
    
        public static Size real() {
            return new Size(REAL_FACTOR);
        }
    
        public static Size custom(int factor) {
            return new Size(factor);
        }
    }