johni
johni

Reputation: 5568

Generalize 3 enums into one type

I'm writing a Java program that does some calculations on files. The program supports 3 types of files (documents, images, videos) with each type allowing only few formats:

enum DocType {
    pdf, doc, docx, xls, xlsx, ppt, pptx
}

enum ImageType {
    bmp, jpg, png, gif, ico
}

enum VideoType {
    avi, mpg, mp4, wmv, mov, flv, swf, mkv
}

In some point in my program, I would like to hold the file extension regardless of the file type, this means that I'd like to be able to do any of the following assignments:

FileType fileExt = DocType.doc
FileType fileExt = ImageType.jpg
FileType fileExt = VideoType.mp4

How can I accomplish that behavior in Java? I know enums cannot extend other enums so basically the elegant solution is not possible.

Thanks

Upvotes: 23

Views: 5223

Answers (3)

Sleiman Jneidi
Sleiman Jneidi

Reputation: 23329

You can declare an interface that governs them all

interface FileType{
}

enum DocType implements FileType{
 PDF // yes, uppercase for constants
 ...
}

enum ImageType implements FileType{
 ....
}

And then you can declare variables of type FileType

FileType file = DocType.PDF;

Upvotes: 35

Shaz
Shaz

Reputation: 1396

One thing you can do is have an enum implements an interface. Here's some example code:

The Interface:

public abstract interface IFileType
{
    public abstract String getExtension();
}

Defined as an ImageType:

public enum ImageType implements IFileType
{
    BMP("bmp"),
    JPG("jpg"),
    PNG("png"),
    GIF("gif"),
    ICO("ico");

    private String extension;

    ImageType(String s)
    {
        extension= s;
    }

    @Override
    public String getExtension()
    {
        return extension;
    }
}

Another definition as a DocType(just so you have an example with two kinds of file types):

public enum DocType implements IFileType
{
    PDF("pdf"),
    DOC("doc"),
    DOCX("docx"),
    XLS("xls"),
    XLSX("xlsx"),
    POWERPOINT("ppt");

    private String extension;

    DocType(String s)
    {
        extension= s;
    }

    @Override
    public String getExtension()
    {
        return extension;
    }
}

A 'File' class to encompass the extension:

public class MyFile
{
    private IFileType fileType;

    public String getExtension()
    {
        return fileType.getExtension();
    }

    public void setType(IFileType t)
    {
        fileType = t;
    }

    public static void main(String[] args)
    {
        MyFile m = new MyFile();
        m.setType(ImageType.BMP);
        System.out.println(m.getExtension());
        m.setType(DocType.POWERPOINT);
        System.out.println(m.getExtension());
    }
}

This is somewhat rough code that I just slapped together for the purpose of showing a few things.

Primarily I wanted to show how you can make each enum adhere to an interface, since I think that's one way to solve what you're trying to do. By making your enums adhere to the interface you get that nice guarantee that you would get with inheritance that the function name(s) are the same, that they've been implemented, etc.

Another thing I wanted to show is the idea of a constructor for an enum. The constructor in this case allows us to create a mapping between the enumeration name (which can be a more human-readable name as I show with DocType.POWERPOINT) and its extension. I'm sure anyone looking at the code would know that PPT == powerpoint, but just wanted to drive home the fact that the name of the thing can be more descriptive if need-be. Also if needed, you can add additional parameters to the constructor, you can have multiple constructors, etc.

One important thing to note is that you can't try to create a new type of the enum from outside the enum itself, like this:

ImageType tiff = new ImageType("tiff"); // 'Cannot instantiate the type ImageType.'

I won't go into further detail since this is already long enough, but it is a good thing that you can't do this. The constructor for an enum is only 'accessible' in the list of initial values (PDF,DOC, etc).

And finally, as David Z mentions in a comment to another answer, you could have MyFile implement the factory design pattern - but I'll leave that as an exercise for the reader.

Edit:

And of course, if you need to know what kind of file type you're dealing with, MyFile can have a function like getFileType, or it could have a series of functions like isDocType, isImageType, etc. The MyFile provided isn't intended to be complete, just an example, after all.

Upvotes: 5

Grisha Weintraub
Grisha Weintraub

Reputation: 7986

You can put all extensions in the same enum with a contentType field that defines the type :

enum FileType {
    PDF(ContentType.DOC),
    DOC(ContentType.DOC),
    // other doc types here ..

    BMP(ContentType.IMAGE),
    JPG(ContentType.IMAGE),
    // other image types here ..

    AVI(ContentType.VIDEO),
    MPG(ContentType.VIDEO),
    // other video types here ..
    ;

    ContentType contentType;

    FileType(ContentType contentType){
        this.contentType = contentType;
    }
}


enum ContentType{
    DOC, IMAGE, VIDEO,
}

Upvotes: 24

Related Questions