代码之家  ›  专栏  ›  技术社区  ›  Esko

如何定义静态工厂方法的通用超级类型?

  •  2
  • Esko  · 技术社区  · 16 年前

    如果已经询问过,请链接并关闭此链接。


    我目前正在为另一个更复杂的API的简化API设计原型。( 潜在的危险 )使用。

    考虑到相关的有点复杂的对象创建,我决定使用静态工厂方法来简化API,目前我有以下一些方法可以按预期工作:

    public class Glue<T> {
    
        private List<Type<T>> types;
    
        private Glue() { types = new ArrayList<Type<T>>(); }
        private static class Type<T> {
            private T value;
            /* some other properties, omitted for simplicity */
            public Type(T value) { this.value = value; }
        }
    
        public static <T> Glue<T> glueFactory(String name, T first, T second) {
            Glue<T> g = new Glue<T>();
            Type<T> firstType = new Glue.Type<T>(first);
            Type<T> secondType = new Glue.Type<T>(second);
    
            g.types.add(firstType);
            g.types.add(secondType);
            /* omitted complex stuff */
            return g;
        }
    }
    

    如前所述,这是按预期工作的。 当API用户( =另一个开发者 类型 Glue<Horse> strongGlue = Glue.glueFactory("2HP", new Horse(), new Horse()); 他得到了他想要的。

    我缺少的是我该如何执行 Horse -或是工厂方法中的任何东西- 总是 实现两者 Serializable Comparable ?只需将它们添加到工厂方法的签名中, <T extends Comparable<T> & Serializable> 在所有情况下都不一定强制执行此规则,仅当使用此简化的API时。这就是为什么我要将它们添加到类的定义中,然后相应地修改工厂方法。

    附言:没有马(绝对没有小马!)在写这个问题时受到了伤害。

    3 回复  |  直到 16 年前
        1
  •  4
  •   Itay Maman    16 年前

    你真的很亲近。这是我的解决方案

    public class Glue<T extends Serializable & Comparable<T>> {
    
      private List<Type<T>> types;
    
      private Glue() { types = new ArrayList<Type<T>>(); }
      private static class Type<T> {
          private T value;
          /* some other properties, omitted for simplicity */
          public Type(T value) { this.value = value; }
      }
    
      public static <V extends Serializable & Comparable<V>> Glue<V> glueFactory(
          String name, V first, V second) {
          Glue<V> g = new Glue<V>();
          Type<V> firstType = new Glue.Type<V>(first);
          Type<V> secondType = new Glue.Type<V>(second);
    
          g.types.add(firstType);
          g.types.add(secondType);
          /* omitted complex stuff */
          return g;
      }
    }
    
    public class Horse implements Serializable, Comparable<Horse> {
      private static final long serialVersionUID = 1156763996034008367L;
    
      @Override
      public int compareTo(Horse o) {
         return 0;
      }      
    }
    
    public class Cat  { }
    
    public static void main(String[] args) {
      Glue<Horse> gh = Glue.glueFactory("2HP", new Horse(), new Horse());
      Glue<Cat> gc = Glue.glueFactory("2C", new Cat(), new Cat()); // <--- Does not compile, as requested!!
    }
    

    此程序在以下方面与您的代码不同:

    • 我重命名了类型参数 T (关于 glueFactory() 方法) V . 如果方法是静态的,那么它的类型参数与包含类类型参数没有关系,因此当两个方法都具有 不同的 名字。
    • 我增加了界限( implements Serializable & Comparable ... )两人的声明 V T

    如预期,结果程序编译 Glue.glueFactory("2HP", new Horse(), new Horse()); 但拒绝 Glue.glueFactory("2C", new Cat(), new Cat());

        2
  •  1
  •   Péter Török    16 年前

    我想唯一合适的解决方案是删除使用您提到的第二个API的可能性,并将您描述的类型约束添加到上面的静态工厂方法中。

    如果您不能取消对第二个API的预测,那么就不能强制执行这样的约束。当然,您可以将适当的接口实现添加到类中,但是第二个API不需要它,因此始终存在一个漏洞,错误可以从中溜走。

        3
  •  0
  •   polygenelubricants    16 年前

    除了泛型类型边界(不重新输入)之外,还可以执行运行时检查(如果需要的话),即。

    if (first instanceof Comparable && first instanceof Serializable) {
       // everything's fine...
    } else {
       throw new IllegalArgumentException("what are you doing?");
    }