return and use different classes in java - java

Not sure if the title does this justice. I am kind of new to Java and trying to figure out how to have a single class use different "services". Let say I have an APIRequest class, this class needs to be able to use different APIs depending on what is needed. Example. I need to ship a package, if the package is below 32OZ I need to use Endicia, else I need to use FedEx. I have 2 "service" classes FedexRequest and EndiciaRequest. I am trying to allow the APIRequest class use either one depending on what the weight of the package. I created a class called APIService that has a static method called getService. it just creates a map of string name -> request class like so...
public class APIService {
private static Map<String, Object> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "FedexRequest");
put("endicia", "EndiciaRequest");
}};
public static Object getService(String type) {
if(services.containsKey(type)) {
return services.get(type);
}
return null;
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
So now I can call APIService.getService("fedex"); however I am having a really hard time trying to figure out how to use that in my APIRequest class, because I would need to do something like...
this.service = (FedexRequest) APIService.getService("fedex");
//or
this.service = (EndiciaRequest) APIService.getService("endicia);
but that breaks the whole dynamic part of the equation, what if I need to add another service later?
I tried having both FedexRequest and EndiciaRequest implement a Request interface, then use
this.service = (Request) APIService.getService("fedex");
but that gives me a Java.lang.Class error saying it cannot be cast to Request. I am assuming it is because Request is an interface so you cannot use cls.newInstance() on an implementing class then cast to the interface.
I am really lost on how to allow my APIRequest class to use either FedexRequest or EndiciaRequest, without specifically using the type casting, so that it can be dynamic and we could add a service later without recoding the whole thing. I come from PHP where this would be extremely simple, since you do not have to explicitly define a type. Any help would be greatly appreciated. Thank you.

If I were you I would do the following:
This is the implementation of Service interface:
public interface Service {
public void performAction();
//other common functions...
}
A small modification to your APIService class:
public class APIService {
private static Map<String, Service> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "com.finity.shipping.api.fedexapi.FedexRequest");
put("endicia", "com.finity.shipping.api.endiciaapi.EndiciaRequest");
}};
public static Service getService(String type) {
return services.get(type);
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
Every time you need a service to be added to your application just implement the Service interface:
public class FedexRequest implements Service {
public void performAction() {
//do something
}
}
And finally in your class where you use this.service:
Service service;
...
this.service = APIService.getService("fedex");
this.service.performAction();

Pooya solution is good.
I will add something. You use some strings to represent things which are typable : constants and classes. Using reflection to initialize a factory where you handle only classes written in hard in some strings(for example com.finity.shipping.api.fedexapi.FedexRequest) and belonging to your own project seems to be a overhead.
In case where your factory don't know which classes it will instantiate, using reflection is meaningful. But it seems not be the case.
Besides, FEDEX and ENDICIA could be constant by using enum. It allows to type them and to avoid bad suprpises.
We would expect that your factory be more simple. Here an example :
public class APIService {
public static enum TypeRequest{
FEDEX, ENDICIA;
}
private static Map<String, Service> services = new HashMap<>();
static {
services.put(FEDEX, new FedexRequest());
services.put(ENDICIA, new EndiciaRequest());
}
public static Service getService(TypeRequest typeRequest) {
return services.get(typeRequest);
}
}

Related

Factory Implementation in Java

After a few years of coding in python, I recently moved to Java for a project.
While working with Python, I had a pretty implementation for a factory.
# file abstract_product.py
from abc import ABC, abstractmethod
class AbstractProduct(ABC):
#abstractmethod
def do_something():
pass
# file product_factory.py
from abstract_product import AbstractProduct
class ProductFactory:
def __init__(self):
self._creators = {}
def get(self, product_name) -> Product:
if product_name not in self._creators:
raise ValueError('No valid implementation !')
return self._creators[product_name]()
def register(self, product_name, product):
self._creators[product_name] = product
product_factory = ProductFactory()
# file product1.py
from abstract_product import AbstractProduct
from product_factory import product_factory
class Product1(AbstractProduct):
def do_something():
# does something
pass
product_factory.register('product1', Product1)
Now the advantage would be, that if I had a new Implementation for
Product, all I had to do was
# file product2.py
from abstract_product import AbstractProduct
from product_factory import product_factory
class Product2(AbstractProduct):
def do_something():
# does something
pass
product_factory.register('product2', Product2)
The advantages of the above approach were:
I had my factory as a singleton. Defining the variable in module ensured that.
Registering a new Product, included no changes to the existing code.
No dirty if else ladder has to be set up any where!
The new implementation registered to the factory in their own module. SO CLEAN :D :D
All the client code needed to know was the product_factory from above and the string parameter based on which the client would get some implementation of Product.
However, now with Java, I am thinking what can I do, to get close to the simplicity and extensibility that the above approach had !
Note:
Please also suggest some other approach that you might have come across for an extensible factory that might even be better than the above !
Your python code can be quite easily translated to Java, and it doesn't look too "foreign".
// could even be an interface
abstract class Product {
// ...
abstract void doSomething();
}
final class ProductFactory {
// not strictly a singleton, to allow you to create multiple factories
// your python code allows this too
private static ProductFactory instance = new ProductFactory();
public static ProductFactory getInstance() {
return instance;
}
private HashMap<String, Supplier<? extends Product>> creators = new HashMap<>();
public void register(String productName, Supplier<? extends Product> creator) {
creators.put(productName, creator);
}
public Product get(String productName) {
Supplier<? extends Product> creator = creators.get(productName);
if (creator == null) {
throw new IllegalArgumentException("No valid implementation !");
}
return creator.get();
}
}
class Product1 extends Product {
#Override
void doSomething() {
}
}
Example of registering and getting a product:
ProductFactory.getInstance().register("product1", Product1::new);
System.out.println(ProductFactory.getInstance().get("product1"));
This is how I like to do it (taken another class example),
public class MyFactory {
private Map<String, MyInterface> factoryMap = new HashMap<>();
#Autowired
public MyFactory(List<MyInterface> listOfObjectsImplementingMyInterface) {
for (MyInterface myInterface : listOfObjectsImplementingMyInterface) {
//Get the class annotation value, use it as map's key
String strategyKey = myInterface.getClass().getAnnotationsByType(Component.class)[0].value();
factoryMap.put(strategy, myInterface);
}
}
// To get an instantiation from factory
public MyInterface getFromFactory(String strategyKey) {
return factoryMap.get(strategyKey);
}
}
The above example is a snippet from a spring f/w project, and with this method you can utilise the spring annotations to populate the factory rather than using messy if/else/switch blocks. The above method can be extended to other cases as well with custom annotations.
In my opinion, a strict conversion from your Python code into Java would be the snippet from below. Show this should feel more familiar to you.
For a simple application, you could make your Factory use static or use the Singleton design pattern to ensure a single instance.
If you are using some frameworks, is quite likely that it offers an alternative that requires less coding though and better testability.
import java.util.HashMap;
import java.util.Map;
// AbstractProduct may better be an 'interface' even
abstract class AbstractProduct {
abstract void doSomething();
}
class Product1 extends AbstractProduct {
#Override
void doSomething() {
System.out.println("I'm Product ONE (1)");
}
}
class Product2 extends AbstractProduct {
#Override
void doSomething() {
System.out.println("I'm Product TWO (2)");
}
}
class ProductFactory {
private final Map<String, Class<? extends AbstractProduct>> creators;
ProductFactory() {
this.creators = new HashMap<>();
}
AbstractProduct get(String productName) {
if (!creators.containsKey(productName)) {
throw new RuntimeException("No valid implementation !");// <-- better define or use a specific exception
}
try {
return creators.get(productName).newInstance(); // <-- Class.newInstance is deprecated since Java9, check docs for replacement
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e); // <-- deal with it properly
}
}
void register(String productName, Class<? extends AbstractProduct> productClass) {
creators.put(productName, productClass);
}
}
public class PythonFactoryThing {
public static void main(String[] args) {
ProductFactory productFactory = new ProductFactory();
productFactory.register("product1", Product1.class);
productFactory.register("product2", Product2.class);
productFactory.get("product1").doSomething();
productFactory.get("product2").doSomething();
productFactory.get("product3").doSomething(); // <-- throws exception
}
}
EDIT: if you don't want a separate place/file to register, you could use a static initialisation block (some Database drivers do that).
You'd have to adapt the above code like this:
Make a singleton out of your Factory:
private ProductFactory() {}// private constructor so nobody else cana instantiate it
public static final ProductFactory INSTANCE = new ProductFactory();
And make each class do something like this:
class Product2 extends AbstractProduct {
static {
ProductFactory.INSTANCE.register("product2", Product2.class);
}
#Override
void doSomething() {
System.out.println("I'm Product TWO (2)");
}
}
But for that to work you would also need to explicitly load the classes you want to have registered. Either by using them some place before using the Factory, or by calling:
Class.forName("Product1");
Since the class loader only loads the classes that are explicitly needed. Which I suppose would be equivalent in Python to importing the file in your script.

How to create instance of generic class with parameters

So I have the following structure:
public abstract class Processor<T extends BaseContainer> {
protected abstract T initializeContainer(String requestID, Map<String, String> details);
protected abstract boolean validateContainer(T request);
protected abstract void process(T request);
public final process(String requestID, Map<String, String> details) {
T request = initializeContainer(requestID, details);
if (!validateContainer(request)) {
process(request);
}
}
}
public abstract class BaseContainer() {
protected final String requestID;
protected BaseContainer(String requestID, Map<String, String> details) {
this.requestID = requestID;
// set some other fields using details
}
}
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
public class SampleProcessor extends Processor<SampleContainer> {
#Override
protected SampleContainer initializeContainer(String requestID, Map<String, String> details) {
return new SampleContainer(requestID, details);
}
}
// SampleContainer can contain other details, but omitted for clarity
public class SampleContainer extends BaseContainer {
public SampleContainer(String requestID, Map<String, String> details) {
super(requestID, details);
}
}
I don't like the fact that I need to override initializeContainer for every Processor I add, especially when I don't change the constructor's parameters of Container (it will be always String requestID, Map<String, String> details
I understand that I can't simple call new T(requestID, details) in Processor. And I would imagine I will need some sort of factory (?) if I want to implement initializeContainer at base class.
Can you help to suggest anyway I can achieve this? Thank you.
Edit 1: I added two more methods to provide better context Processor
Everythings fine
This is a pattern called the abstract-factory.
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
This is the main intend of the pattern (ebenda)
the client (you) software creates a concrete implementation (your SampleProcessor) of the abstract factory (Processor) and then uses the generic interface of the factory to create (via initializeContainer) the concrete objects (your SampleContainer)...
I'd refactor the method name to createContainer, because that's what you do with your implementation - you don't setup an existing one but the make a new one.
Your simple example only calls the container constructor. But the 'processor creation and initialization' process could vary. Maybe, some processors for some container need special treatment. Then the implementations of the method would look different for each container subclass again.
An alternative common pattern, to solve this common problem, would be adding another abstract method like
public abstract Class<T> getProcessorType();
and implement it like this on every container implementation:
#Override
public Class<MyProcessor> getProcessorType() {
return MyProcessor.class;
}
The base class then could implement the create method for processors:
public T createProcessor(String requestID, Map<String, String> details) {
T processor;
try {
processor = getProcessorType().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace(); // or handle correctly
}
processor.init(requestId, details)
return processor;
}
(Note that this requires a no-args processor constructor)

Best Practice/Pattern for Transforming Java Objects

Let's say I have an application that is responsible for taking a vendor message and converting into a canonical message. For example:
public class MessageA extends VendorMessage { ... }
public class MessageB extends VendorMessage { ... }
public class MessageX extends CanonicalMessage { ... }
public class MessageY extends CanonicalMessage { ... }
Where MessageA maps to MessageX and MessageB maps to MessageY.
My approach is that I have one transformer class per message type to handle this conversion. In this example, I would have the following transformers:
public class MessageXTransfomer()
{
public MessageX transform(MessageA message) {...}
}
public class MessageYTransfomer()
{
public MessageY transform(MessageB message) {...}
}
My questions is really with the way I would ultimately invoke the transformers.
Since my process takes some VendorMessage as an input, I need to interrogate the type so I know which specific transformer to direct it to. For example, one approach might look like this:
public class TransfomerService
{
MessageXTransformer messageXTransformer = new MessageXTransformer();
MessageYTransformer messageYTransformer = new MessageYTransformer();
public CanonicalMessage transform(VendorMessage message)
{
if (message instanceOf MessageA)
{
return messageXTransformer.transform((MessageA) message);
}
else if (message instanceOf MessageB)
{
return messageYTransformer.transform((MessageB) message);
}
}
}
I'm not sure why, but I this approach just feels strange - as if I'm doing something wrong. Is there a best practice for this kind of problem that I should be using?
Note: I'm looking for the best approach without using any transformation frameworks, etc. Ideally, the pattern would be achievable using just basic Java.
I like the answer of #javaguy however it is not complete. Of course it will be nice if you could use the specific transformer like in his later example, but if you can't you have to stick with TransformerFacade and kind of a StrategyPattern:
public class TransformerFacade {
private Map<Class, VendorMessageToCanonicalMessageTransformer> transformers = new HashMap<>();
{
// this is like strategies, the key may be class, class name, enum value, whatever
transformers.put(MessageA.class, new MessageXTransformer());
transformers.put(MessageB.class, new MessageYTransformer());
}
public CanonicalMessage transform(VendorMessage message) {
return transformers.get(message.getClass()).transform(message);
}
}
I would simply let every concrete VendorMessage return its corresponding CanonicalMessage by implementing an interface:
public interface Mapper<T> {
T map();
}
Then, MessageA should implement this interface:
public MessageA implements Mapper<MessageX> {
#Override
public MessageX map() {
MessageX message = ...;
// fill message
return message;
}
}
If you don't want to do the mapping in the VendorMessage class, then a strategy as suggested by Vadim Kirilchuk in his answer would do the trick.

Factory pattern: Accessing child methods

I have two classes CashStore and DrinkStore, both extends from Store. I have a StoreFactory class (returns Store object) to instantiate objects for clients. I want to access methods specific to child classes from these clients. How do I do it without casting? If I used casting, would it break the pattern, since now the clients know about the Child classes?
class Store{
A(){}
B(){}
}
class CashStore{
A(){}
B(){}
C(){}
D(){}
}
//impl for drink store and other stores
class StoreFactory{
public Store getStore(String type){
//return a Store obj based on type DrinkStore or CashStore
}
}
class Client{
StoreFactory fac;
public Client(){
fac = new StoreFactory();
Store s = fac.getStore("cash");
s.C(); //requires a cast
}
}
Does casting break my pattern?
Factory pattern is used to decouple from runtime type. For example, when it's platform- or layout-specific, and you don't want your client code to mess with it. In your case you do need an exact type, so it seems factory pattern isn't a good choice. Consider using simple static methods, like:
class Stores {
static CashStore createCashStore() {
return new CashStore();
}
static DrinkStore createDrinkStore() {
return new DrinkStore();
}
}
So basically you need to access child specific methods without casting. That's the whole purpose of Visitor pattern.
You can switch between different child by using method overloading. I have given an example below, you would need to adapt that to fit into your code. And also you should take out the business logic from the constructor (of Client) and implement them inside methods.
public class Client{
public void doSomething(CashStore cs){
cs.c();
//you can call methods specific to CashStore.
}
public void doSomething(DrinkStore ds){
ds.e();
//you can call methods specific to DrinkStore.
}
}
I want to access methods specific to child classes from these clients.
How do I do it without casting?
If you know the expected type, then you can use generics to avoid casting:
interface Store {
}
class WhiskeyStore implements Store {
}
class VodkaStore implements Store {
}
class StoreFactory {
<T extends Store> T getStore(Class<T> clazz) {
try {
// I use reflection just as an example, you can use whatever you want
return clazz.getConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Cannot create store of type: " + clazz, e);
}
}
}
public final class Example {
public static void main(String[] args) {
WhiskeyStore whiskeyStore = new StoreFactory().getStore(WhiskeyStore.class);
VodkaStore vodkaStore = new StoreFactory().getStore(VodkaStore.class);
}
}

Factories in Java without a switch statement

I am trying to build a factory object, but having trouble working out a good way of doing it in Java.
The application I am writing is used for processing files in various formats, so there is a CodecInterface which applies to all classes which are used for reading and writing files. Let's assume it defines the following methods. Each of these files has a unique human-designated ID string which is used for id'ing the encoder\decoder.
String read();
void write(String data);
String getID();
The factory class would have a create method which is intended to create instances of these codec classes. I imagine the method signature would look something like this.
static CodecInterface CodecFactory.create(String filename, String codecid, String args);
The filename is the name of the file to read/write, and the codecid is the unique ID indicating what codec to use. The args parameter is a string of arguments passed to the decoder/encoder object being generated. The return of this should be an instance of the requested codec object.
All of the Factory examples I have seen typically have a switch statement inside of the create method which creates an object instance dependent on the ID. I want to avoid doing it this way as it doesn't seem like the 'right' way, and it also means that the list is more or less fixed unless you modify the create method. Ideally I would like to use something like a dictionary (indexed by the codec ID) which contains something which can be used to create an instance of the codec classes I want (I will call this mystery class ClassReference). Again to use some quasi-java code, here is what I was thinking as the body for the create method.
static Dictionary<String, ClassReference>;
static CodecInterface CodecFactory.create(String filename, String codecid, String args);
{
ClassReference classreference;
classreference = codeclibrary(codecid);
return classreference.instanceOf(args);
}
The dictionary of ID's is easy enough, but I can't work out what ClassReference should be. Class Reference should allow me to create an instance of the desired class, as in the example above.
From looking around online, the class method, and instanceOf seem to be heading in the right direction, but I haven't found anything which puts the two together. As an added complication, the constructors for the objects being created will have arguments.
Any tips on what I should be looking at would be greatly appreciated.
Thanks in advance.
SOLUTION
Thanks everyone for your advice. I've ended up taking bits and pieces from all of your suggestions and came up with the following which seems to work as I wanted.
Note that I have omitted much of the sanity\error checking code to show off the important bits.
import java.lang.reflect.Constructor;
import java.util.HashMap;
public class CodecFactory
{
private static HashMap<String, Class<? extends CodecInterface>> codecs;
static
{
codecs = new HashMap<String, Class<? extends CodecInterface>>();
//Register built-in codecs here
register("codecA", CodecA.class);
register("codecB", CodecB.class);
register("codecC", CodecC.class);
}
public static void register(String id, Class<? extends CodecInterface> codec)
{
Class<? extends CodecInterface> existing;
existing = codecs.get(id);
if(existing == null)
{
codecs.put(id, codec);
}
else
{
//Duplicate ID error handling
}
}
public static CodecInterface create(String codecid, String filename, String mode, String arguments)
{
Class<? extends CodecInterface> codecclass;
CodecInterface codec;
Constructor constructor;
codec = null;
codecclass = codecs.get(codecid);
if(codecclass != null)
{
try
{
constructor = codecclass.getDeclaredConstructor(String.class, String.class, String.class, String.class);
codec = (CodecInterface)(constructor.newInstance(codecid, filename, mode, arguments));
}
catch(Exception e)
{
//Error handling for constructor/instantiation
}
}
return codec;
}
}
There's a zillion options. For example, you might create a base factory class that also has static methods to manage registered factories (untested code typed here, sorry for errors):
public abstract class CodecFactory {
private final String name;
public CodecFactory (String name) {
this.name = name;
}
public final String getName () {
return name;
}
// Subclasses must implement this.
public abstract Codec newInstance (String filename, String args);
// --- Static factory stuff ---
private static final Map<String,CodecFactory> factories = new HashMap<String,CodecFactory>();
public static void registerFactory (CodecFactory f) {
factories.put(f.getName(), f);
}
public static Codec newInstance (String filename, String codec, String args) {
CodecFactory factory = factories.get(codec);
if (factory != null)
return factory.newInstance(filename, args);
else
throw new IllegalArgumentException("No such codec.");
}
}
Then:
public class QuantumCodecFactory extends CodecFactory {
public QuantumCodecFactory {
super("quantum");
}
#Override public Codec newInstance (String filename, String args) {
return new QuantumCodec(filename, args);
}
}
Of course this means at some point you must:
CodecFactory.registerFactory(new QuantumCodecFactory());
Then usage is:
Codec codec = CodecFactory.newInstance(filename, "quantum", args);
Another option is to use reflection and maintain a Map<String,Class<? extends CodecInterface>>, using Class.newInstance() to instantiate. This is convenient to implement because it works on top of Java's Class, which already supports a factory-style model for instantiating objects. The caveats are, like above the classes must be explicitly registered, and also (unlike above) you can't implicitly enforce constructor parameter types at compile-time (although you could at least abstract it behind some method instead of calling Class.newInstance() directly from client code).
For example:
public final class CodecFactory {
private static final Map<String,Class<? extends Codec>> classes = new HashMap<String,Class<? extends Codec>>();
public static void registerClass (String name, Class<? extends Codec> clz) {
classes.put(name, clz);
}
public static Codec newInstance (String filename, String codec, String args) {
Class<? extends Codec> clz = classes.get(codec);
if (clz != null)
return clz.getDeclaredConstructor(String.class, String.class).newInstance(filename, args);
else
throw new IllegalArgumentException("No such codec.");
}
}
Where every Codec is expected to have a constructor that takes (String filename, String args). Registration, then, is:
CodecFactory.registerClass("quantum", QuantumCodec.class);
Usage is the same as above:
Codec codec = CodecFactory.newInstance(filename, "quantum", args);
You could even leave out the map and just use Class.forName() -- this doesn't give you as much flexibility with codec names, but it essentially lets the class loader do all of the work for you and you don't need to explicitly register types ahead of time.
Edit: Re: Question in comments below. You could come up with a system that combined the two above examples to create a reusable, reflection based generic factory derived from CodecFactory, which still leaves you with the ability to create other more specialized factories, e.g.:
public class GenericCodecFactory extends CodecFactory {
private final String name;
private final Class<? extends Codec> clz;
public GenericCodecFactory (String name, String clzname) {
this.name = name;
this.clz = Class.forName(clzname);
}
public GenericCodecFactory (String name, Class<? extends Codec> clz) {
this.name = name;
this.clz = clz;
}
// parameter type checking provided via calls to this method, reflection
// is abstracted behind it.
#Override public Codec newInstance (String filename, String args) {
return clz.getDeclaredConstructor(String.class, String.class).newInstance(filename, args);
}
}
Then you could use that for whatever:
// you can use specialized factories
ClassFactory.registerFactory(new QuantumCodecFactory());
// you can use the generic factory that requires a class at compile-time
ClassFactory.registerFactory(new GenericCodecFactory("awesome", AwesomeCodec.class));
// you can use the generic factory that doesn't need to have class present at compile-time
ClassFactory.registerFactory(new GenericCodecFactory("ninja", "com.mystuff.codecs.NinjaCodec"));
As you can see, there's a ton of possibilities. Using Class.forName() in reflection-based factories is nice because the class doesn't need to be present at compile-time; so you can drop in codec classes on the class path and, say, specify a list of class names in a run-time configuration file (then you could have static ClassFactory.registerFactoriesListedInFile(String confgFilename) or something), or scan a "plugin" directory. You can even construct class names from simpler strings, if you're comfortable with that, e.g.:
public class GenericPackageCodecFactory extends GenericCodecFactory {
public GenericPackageCodecFactory (String name) {
super(name, "com.mystuff." + name + ".Codec");
}
}
You could even use something like that as a fallback in ClassFactory if the codec name is not found, to get around having to explicitly register types.
The reason reflection keeps popping up, by the way, is that it's very flexible and the Class interface is essentially an all-encompassing class factory, so it frequently parallels what specific factory architectures are trying to accomplish.
Another option is to use the second example I mentioned above (with the Map<String,Class>) but make a version of registerFactory that takes a String class name instead of a Class, similar to the generic implementation I just mentioned. That's probably the least amount of code required to avoid having to create instances of CodecFactorys.
I can't possibly give examples for every combination of things you can do here, so here is a partial list of the tools you have available, which you should use as you see fit. Remember: Factories are a concept; it's up to you to use the tools you have to implement that concept in a clean way that meets your requirements.
Reflection (Class<?> and Class.forName)
Static initializer blocks (sometimes a good place to register a factory; requires class to be loaded, but Class.forName can trigger this).
External configuration files
Plugin frameworks like http://jpf.sourceforge.net/ or https://code.google.com/p/jspf/ or https://code.google.com/p/jin-plugin/ (good comparison of OSGi, JPF, JSPF can be found here; I've never heard of jin-plugin prior to looking through the answers in the link).
Maps of registered factories and/or ability to use reflection to generate class names on the fly.
Don't forget concurrent maps and/or synchronization primitives for multi-threaded support if necessary.
Lots of other stuff.
Also: Don't go crazy implementing all of these possibilities if you don't have to; think about your requirements and decide on the minimum amount of work you need to do here to meet them. For example, if you need extensible plugins, JSPF alone might be enough to satisfy all of your requirements without you having to do any of this work (I haven't actually checked it out, so I'm not sure). If you don't need that kind of plugin "scanning" behavior, simple implementations like the examples above will do the trick.
Try something like that:
public class CodecFactory {
final private static Map<String, Class<? extends CodecInterface>> codecLibrary;
static {
codecLibrary = new HashMap<String, Class<? extends CodecInterface>>();
codecLibrary.put("codec1", Codec1.class);
//...
}
static CodecInterface create(String filename, String codecid, String args) throws InstantiationException, IllegalAccessException {
Class<? extends CodecInterface> clazz;
clazz = codecLibrary.get(codecid);
CodecInterface codec = clazz.newInstance();
codec.setArgs(args);
codec.setFilename(filename);
return codec;
}
}
You can use enum as well, just like below :
interface CodecInterface {
}
class CodecA implements CodecInterface {
}
class CodecB implements CodecInterface {
}
class CodecC implements CodecInterface {
}
enum CodecType {
codecA {
public CodecInterface create() {
return new CodecA();
}
},
codecB {
public CodecInterface create() {
return new CodecB();
}
},
codecC {
public CodecInterface create() {
return new CodecC();
}
};
public CodecInterface create() {
return null;
}
}
class CodecFactory {
public CodecInterface newInstance(CodecType codecType) {
return codecType.create();
}
}

Categories