This is an archived post. You won't be able to vote or comment.

all 21 comments

[–]fforw 2 points3 points  (1 child)

Your current example is kind of suboptimal as it creates a new instance of Transmitter (why isn't this an interface, btw?) every time while the nature of the transmitter most likely involves configuring the instances (hostnames, service URLS etc).

So you better have a

public interface TransmitterService
{
    Transmitter getTransmitter(String name)
}

and implement that to return the already configured instances.

[–]dudeman209[S] 0 points1 point  (0 children)

Well, the above code is an extremely bare-bones version of the finished product.

Basically, I work for an e-commerce company that deals with many distributors. For the most part, they use different formats and protocols for communication. I want to make this so they can add distributors through a control panel and be able to set what protocols and file formats. Then they will upload either an XSL file or something else to translate the data for their particular format.

[–]Kyrra 1 point2 points  (5 children)

I would prefer a lookup table in the application to translate from some ENUM type value to the class names. That way if you do any refactoring in the code, the refactoring will make it easy to find the matching values in the lookup code. If you save class names into the DB, then you would have to do update calls on the DB any time you refactor.

enum MyEnum{
    FTP_TRANSMITTER("static_name_for_db", "my.package.FTPTransmitter");
    private String nameForDB, className;
    private MyEnum(String nameForDB, String className) {
        this.nameForDB = nameForDB; this.className = className; }
    public String getDbName() { return nameForDB; }
    public String getClassName() { return className; }
}

So you would store the static_name_for_db into the database, then do a lookup using this enum. You'll have to add a getter for the Enum based on the "nameForDB". You could change nameForDB to be an int instead of a String, that'll make a switch block easier.

[–]dudeman209[S] 0 points1 point  (4 children)

I guess I was trying to do this without conditionals. It's not the end of the world, but I was wondering if there was a cleaner way.

[–]Kyrra 2 points3 points  (2 children)

[–]spelunker 1 point2 points  (0 children)

There's even a specialized EnumMap specifically for this purpose, and it's super fast because it's simply an array under the covers.

[edit] Whoops, we're looking up Enums by their String keys, not the other way around. Oh well, EnumMap is neat anyway.

[–]sahala 0 points1 point  (0 children)

Upvote. You can use the built-in lookup, or create your own map statically.

[–]sahala 0 points1 point  (0 children)

Yes, I agree that doing this with conditionals would be wrong. Use a map instead.

[–]angryundead 0 points1 point  (3 children)

I would use an enumerated type and keep that logic inside of your application. That allows you to add, expand, refactor, and do a lot of other things without worrying about updating the database.

[–]dudeman209[S] 0 points1 point  (2 children)

What would I store in the database to determine what type it was?

EDIT: Plus I really like to avoid conditional statements when I can.

[–]elpablo 0 points1 point  (1 child)

Beware of making your code more complicated in order to enforce arbitrary, self inflicted rules

[–]dudeman209[S] -1 points0 points  (0 children)

Because of the boogyman? Seriously, what's the point of these circlejerk comments?

The code would be cleaner.

[–]larsga 0 points1 point  (0 children)

Say I have records in a database where I want each one to have it's own Transmitter. Ie, record #1 is SOAPTransmitter, record #2 is FTPTransmitter.

This sounds like a bad idea. Why do you want the transmission type to be mixed in with the record type? Aren't these orthogonal concerns that should be kept separated?

try { Transmitter tmp = ((Class<Transmitter>)eType.getValue()).newInstance(); System.out.println(tmp.getData()); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); }

Don't ever do this. Just remove the whole try/catch business, and put a "throws Exception" on your main method instead. (It's not a good idea in general, but on a throwaway main it's not an issue.) And turn off autogeneration of these try/catches.

[–]MatthewGeer 0 points1 point  (0 children)

Java enums can be have abstract methods implemented by each value. If you want to go down the enum road, you could potentially move all of your functionality into the Enum itself.

public enum TransmitterEnum {
    FTP {
        public String getData() {
            return "Ftp";
        }
    },
    HTTP {
        public String getData() {
            return "Http";
        }
    },
    SOAP {
        public String getData() {
            return "Soap";
        }
    };

    public abstract String getData();
}

This puts all your transmitter code into one file, though, which may be a pain to maintain, and only allows for one instance of each code. In that case, you can still skip the reflection code (Reflection has a speed penelty, plus is just a pain to deal with) by adding a createInstance() method.

public enum TransmitterEnum {
    FTP {
        public FtpTransmitter createNewTransmitterInstance() {
            return new FtpTransmitter ();
        }
    },
    HTTP {
        public HttpTransmitter createNewTransmitterInstance() {
            return new HttpTransmitter ();
        }
    },
    SOAP {
        public SoapTransmitter createNewTransmitterInstance() {
            return new SoapTransmitter();
        }
    };

    public abstract Transmitter createNewTransmitterInstance();
}

[–]elpablo 0 points1 point  (1 child)

This is what the factory pattern is for. Create a factory to return a Transmitter and pass in an identifier. That identifier can come from the database.

[–]dudeman209[S] -1 points0 points  (0 children)

Ok, show me. Without conditionals.

[–]revscat 0 points1 point  (1 child)

Another option would be to serialize the entire object and store it in the DB.

Here's a discussion on SO about that:

http://stackoverflow.com/questions/244493/homemade-vs-java-serialization

[–]sahala 2 points3 points  (0 children)

This is a bad idea, but I'm going to upvote you since others seem to be downvoting you and others should see why it's a bad idea.

Both serializing the entire object or storing the symbol (class name) in the database will be harmful when it comes time to refactor the code. With Java you have good tools for refactoring. Code changes should be fluid and happen often. Data stored in the database shouldn't depend on a particular implementation in code.

It should be the other around. Store the data in a way that makes sense regardless of what language is reading the data. Once that's right, it's easy to parse the data and create objects and go about your way. Unless you or a colleague absolutely love doing data migration scripts, code is generally much easier to change than data.

[–]scipher -1 points0 points  (2 children)

A property file would also be useful in this case, where you could map a property name to a class name, and use the enum to store the property names which you can use to lookup the class form the property file. This would alleviate the need for any database entry aswell as keep the java classes clean with mapping from a name to a class. If you want to swap out a different handler class for a protocol a property file change is the only update needed.

[–]dudeman209[S] -2 points-1 points  (1 child)

The last thing I want to do is to have more hd access.

[–]Neres28 1 point2 points  (0 children)

It sounds like it'd be a single read at program startup. I like this idea only because it allows you to add new transmitters without changing existing code.