I have a "generic" cache object:
public class Cache {
private static final Map<Class, ICacheable> cacheMap = new HashMap<>();
public static ICacheable getCacheableElement(Class cacheableElementClass, Object... params) {
ICacheable cacheableElement = cacheMap.get(cacheableElementClass);
if (cacheableElement == null) {
cacheableElement = addIfNotExists(cacheableElementClass, params);
}
return cacheableElement;
}
private static ICacheable addIfNotExists(Class cacheableElementClass, Object... params) {
ICacheable cacheableElementAdded;
if (cacheableElementClass.equals(SourceCode.class)) {
cacheMap.put(cacheableElementClass, new SourceCode((String) params[0]));
} else if (cacheableElementClass.equals(SymbolTable.class)) {
cacheMap.put(cacheableElementClass, new SymbolTable());
} else {
// Error!
throw new NullPointerException();
}
cacheableElementAdded = cacheMap.get(cacheableElementClass);
return cacheableElementAdded;
}
}
The Cache
's responsibility is cache any kind of object. For that reason, I have the method's param params
(I need to find a better name). params
is for those objects which need a param for its creation. For example:
public class SourceCode implements ICacheable {
private String sourceCode;
public static final Character EOF = '#';
public SourceCode(String sourceCode) {
this.sourceCode = sourceCode.toUpperCase() + EOF;
}
}
As you can see, SourceCode
needs a String
param (sourceCode) for its creation.
In some part of the code, I fill the cacheMap
... In the case of the SourceCode
:
cacheMap.put(cacheableElementClass, new SourceCode((String) params[0]));
Here is my problem. As you can see, I create the SourceCode
object with the first element of params
array (remember the varargs
in the above method's signature). IMHO, this is not a clean solution, because some objects will use the params
array (SourceCode
), and others won't use it.
Is there a design pattern or a better way to refactoring this?
EDIT: This is the solution I created:
As you can see, each object will have its own cache object (implementing ICache
interface). Also,I have a CacheFactory
which responsibility is create the cache object and returning it if it was already created.
Here is the code:
ICache:
public interface ICache {
public Object getCacheableElement(Object... params);
}
CacheFactory
public class CacheFactory {
private static final Map<Class<?>, ICache> caches = new HashMap<>();
public static ICache createCache(Class cacheClass) {
Boolean isICacheType = isICacheType(cacheClass);
if (isICacheType) {
if (caches.containsKey(cacheClass)) {
return caches.get(cacheClass);
} else {
try {
ICache cache = (ICache) cacheClass.getConstructor().newInstance();
caches.put(cacheClass, cache);
return cache;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
// TODO: Is this safe? If not, FIX IT!
System.err.println(ex.getMessage());
throw new NullPointerException();
}
}
} else {
throw new IllegalArgumentException(String.format("Class \"%s\" not supported yet.",
cacheClass.getClass().getName()));
}
}
private static Boolean isICacheType(Class cacheClass) {
Boolean isICacheType = false;
Class[] interfaces = cacheClass.getInterfaces();
for (Class crtInterface : interfaces) {
if (crtInterface.equals(ICache.class)) {
isICacheType = true;
break;
}
}
return isICacheType;
}
}
SourceCodeCache:
public class SourceCodeCache implements ICache {
private SourceCode sourceCode = null;
@Override
public Object getCacheableElement(Object... params) {
sourceCode = (sourceCode == null) ? new SourceCode((String) params[0]) : sourceCode;
return sourceCode;
}
}
SymbolTableCache:
public class SymbolTableCache implements ICache {
private SymbolTable symbolTable;
@Override
public Object getCacheableElement(Object... params) {
symbolTable = (symbolTable == null) ? new SymbolTable() : symbolTable;
return symbolTable;
}
}
Thanks to all of you for your recommendations and advices. It was a real pleasure.