3
\$\begingroup\$

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?

\$\endgroup\$
4
\$\begingroup\$

I'm afraid, it's hard to use. To create a size, I need to do something like

new DevicePreDefinedImageSize(
    DevicePreDefinedImageSizeMode.REAL_SIZE,
    number)

I don't think I could ever remember this. What about:

Size.newRealSize(number)

This can be done easily, all you need are three static methods. You can otherwise keep you classes as they are.


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

This is a real pain. I can see that there's no downSampleFactor, but throwing four question marks isn't really helpful. I'd return 0. Though it may hide errors, it can make it easier to use.

Or, when you're defining so many classes, what about making them so that the unwanted method doesn't really exist? Declare it only where it makes sense.


Personally I wouldn't do six classes for this.

\$\endgroup\$
  • \$\begingroup\$ +1, thank you for your times.I agree with you,that way is hard to use.I answer to my question. \$\endgroup\$ – hasanghaforian Apr 21 '15 at 7:26
1
\$\begingroup\$

Your solution seems overcomplicated to me. I doubt that all this is really necessary for obtaining a single int value that should be provided by developers. What you seem to want here is a IntSupplier

This is about as simple as it can get. You want an int, you can get it from an IntSupplier

And allowing your own options suddenly becomes as simple as making public static instances available for developers to use, which is quite similar to enums

\$\endgroup\$
  • \$\begingroup\$ Thank you! But I use java 7. \$\endgroup\$ – hasanghaforian Apr 21 '15 at 4:22
  • \$\begingroup\$ IntSupplier is an interface. Java 8 only adds the additional benefit of allowing a lambda expression to be used instead of an anonymous inner class \$\endgroup\$ – Vogel612 Apr 21 '15 at 7:31
0
\$\begingroup\$

Like @maaartinus I think it is hard to use the way that I display in question.So I asked another question and it seems this answer may be a good approach.I edit that answer and add it below:

public enum ImageSizeMode{
    CUSTOM_SIZE,THUMBNAIL, REAL_SIZE;
}


public class Size {
    private static final int THUMBNAIL_FACTOR = -1;
    private static final int REAL_FACTOR = -1;
    private final int sampleFactor;
    private final ImageSizeMode mode;

    private Size(int sampleFactor, ImageSizeMode mode) {
        this.sampleFactor = sampleFactor;
        this.mode = mode;
    }

    public static Size thumbnail() {
        return new Size(THUMBNAIL_FACTOR, ImageSizeMode.THUMBNAIL);
    }

    public static Size real() {
        return new Size(REAL_FACTOR, ImageSizeMode.REAL_SIZE);
    }

    public static Size custom(int factor) {
        return new Size(factor, ImageSizeMode.CUSTOM_SIZE);
    }

    public int getSampleFactor() {
        return sampleFactor;
    }

    public ImageSizeMode getMode() {
        return mode;
    }
}

This code is smaller than the way that was displayed in my question and also it is easy to use it:

Size realSize = Size.real();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.