Java匿名类唯一标识

时间:2014-10-09 12:04:32

标签: java oop design-patterns reflection

假设我想使用使用匿名类的Command模式。在Invoker中我想应用缓存。像这样:

// command abstract class
public static abstract class ViewScopeCacheCommand<T> { 
    public abstract T invoke();
}

// innvoker
public static class ViewScopeCache<T> {
    // cache
    private Map<String,T> pageCache = null;

    public ViewScopeCache() {
        pageCache = new HashMap<String,T>();
    }
    // get from cache
    public T get(String key) {
        return pageCache.get(key);
    }
    // put to cache
    public void put(String key, T t) {
        pageCache.put(key, t);
    }
    // I want to say how to load the result of not in cache - given by command
    public T getLazy(String key, ViewScopeCacheCommand<T> command) {
        if(get(key) == null) {

            T t = command.invoke();
            pageCache.put(key, t);
        }
        return get(key);
    }
    public void invalidate() {
        pageCache.clear();
    }
    // I want to identify the cache by command
    /*
    public T getLazy(ViewScopeCacheCommand<T> command) {
        String magicKey = .. derive from command
        if(get(key) == null) {

            T t = command.invoke();
            pageCache.put(key, t);
        }
        return get(key);
    }
    */ 
}

假设我有两个使用它的位置:

..
Result getResult1() {
    viewScopeCache.get("key1", new ViewScopeCacheCommand<Result>() { 
       ..invoke(){ call DB SQLX }}); // does not need to be SQL, can be a service A call
}
..
Result getResult2() {
    viewScopeCache.get("key2", new ViewScopeCacheCommand<Result>() { 
       ..invoke(){ call DB SQLY}}); // does not need to be SQL, can be a service B call
}
..

确定这项工作但我可以识别匿名的ViewScopeCacheCommand吗?这样用法会简化这个

..
Result getResult1() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>() { 
       ..invoke(){ call DB SQLX }}); // does not need to be SQL, can be a service A call
}
..
Result getResult2() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>() { 
       ..invoke(){ call DB SQLY}}); // does not need to be SQL, can be a service B call
}
..

如果我已经完成了普通的类扩展,我可以使用instanceof,反射等。但是有一些机制来识别调用SQLX的command1和调用SQLY的命令2之间的区别 它可能是基于反射的,它可能是代码行..

我心中唯一的想法是注释:( ..但这很蹩脚..

一些更好的主意/建议?

问题是:我可以推断出在类级别上可能是唯一的Key来识别特定的命令..

我可以在Command {abstract String getUniqueKey(){}}中添加第二个方法并强制它被定义..但那很丑:)

2 个答案:

答案 0 :(得分:1)

抽象类可以有匿名类可以调用的构造函数:

public static abstract class ViewScopeCacheCommand<T> {
    private final String uniqueKey;

    public ViewScopeCacheCommand(String uniqueKey) {
        this.uniqueKey= uniqueKey;
    }

    public String getUniqueKey() {
        return uniqueKey;
    }

    public abstract T invoke();
}

用法如下:

..
Result getResult1() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>("key1") { 
        ..invoke(){ call DB SQLX }}); // does not need to be SQL, can be a service A call
}
..
Result getResult2() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>("key2") { 
        ..invoke(){ call DB SQLY}}); // does not need to be SQL, can be a service B call
}
..

答案 1 :(得分:0)

奥利弗查尔斯沃思在评论中提出:

匿名类在JVM级别上并不是真正的匿名。它仍然有一个与之关联的唯一Class实例。

他是正确的,内部(匿名)类在JVM级别上有唯一的标识符。

这是我的测试:

public class Demo {

public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
        loop();
    }
}

private static void loop() {
    test(new TestMe() {

        @Override
        int getKey() {
            return 100;
        }
    });
    test(new TestMe() {

        @Override
        int getKey() {
            return 200;
        }
    });
}   
public abstract static class TestMe {
    abstract int getKey();
}   
public static void test(TestMe testMe) {
    System.out.println(testMe.getClass() + " " + testMe.getKey());
}   
}

输出

class Demo$1 100
class Demo$2 200
class Demo$1 100
class Demo$2 200
class Demo$1 100
class Demo$2 200
class Demo$1 100
class Demo$2 200

因此问题中的代码可以简化为

// command abstract class
public static abstract class ViewScopeCacheCommand<T> { 
    public abstract T invoke();
}

// innvoker
public static class ViewScopeCache<T> {
   // cache
   private Map<String,T> pageCache = null;

   public ViewScopeCache() {
      pageCache = new HashMap<String,T>();
   }
   // get from cache
   public T get(String key) {
       return pageCache.get(key);
   }
   // put to cache
   public void put(String key, T t) {
       pageCache.put(key, t);
   }
   /*
   // I want to say how to load the result of not in cache - given by command
   public T getLazy(String key, ViewScopeCacheCommand<T> command) {
       if(get(key) == null) {
           T t = command.invoke();
           pageCache.put(key, t);
    }
    return get(key);
   }
   */
   public void invalidate() {
       pageCache.clear();
   }
   // I want to identify the cache by command
   /*** solution ***/
   public T getLazy(ViewScopeCacheCommand<T> command) {
       String magicKey = command.getClass().toString(); // <--- solution
       if(get(key) == null) {
           T t = command.invoke();
           pageCache.put(key, t);
       }
       return get(key);
   }
}

使用惰性用例(将结果放入缓存并加载,如果缓存中不存在,则加载):

..
Result getResult1() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>() { 
      ..invoke(){ call anything X }}); // does not need to be SQL, can be a service A call
}
..
Result getResult2() {
    viewScopeCache.get(new ViewScopeCacheCommand<Result>() { 
     ..invoke(){ call anything Y}}); // does not need to be SQL, can be a service B call
 }
..

我当然也可以覆盖我只需要密钥的情况:

Result getResult3() {
    if(something empty) {
       //fetch it
       viewScopeCache.put("key3",..Z..);
    }
    viewScopeCache.get("key3");
 }
..

感谢大家的讨论和解决。