如何使用Java Generics从String中撤回T

时间:2015-05-08 11:03:41

标签: java generics

我正在尝试将Java泛型用于我的特定用例。有一个通用类Node,在这个例子中会有很多像NodeBoolean这样的实现类。

public abstract class Node<T>
    {
        T defaultValue;

        public Node(T defaultValue) {
            this.defaultValue = defaultValue;
        }

        protected abstract T parse(String input) ;
        public T getValue()
        {
            try
            {
                // here will be some logic to get String value from some db or any other source
                String input = "true";
                return parse(input);
            } catch (Exception e) {
                return defaultValue;
            }
        }
    }

实施班级

class NodeBoolean extends Node<Boolean>
{
    public NodeBoolean(Boolean defaultValue) {
        super(defaultValue);
    }

    @Override
    protected Boolean parse(String input) {
        return Boolean.parseBoolean(input);
    }
}

测试类

class TestNode
{
    public static void main(String[] args) {
        NodeBoolean node =  new NodeBoolean(true);
        System.out.println(node.getValue());
    }
}

我使用这种方法遇到的问题

  1. 假设类Node的构造函数有多种变体,那么所有实现类也需要定义它们以实现可见性。使用Builder模式可以解决这个问题,但我只是想知道其他可能的解决方案。

  2. 将会有很多实现类只有一个覆盖方法parse。我正在寻找一种在泛型类instanceof本身的给定示例中基于defaultValue Node来定义所有不同解析器的方法。然后,此Node课程不是abstract

  3. 我希望在创建parse对象时,提供定义String方法的功能,该方法需要T并根据用户需求返回Node的值阶级本身。通过这种方式,如果我只有一次特定对象类型Node可以创建,而无需定义任何新的实现类。

  4. 我正在寻找解决3个以上问题的解决方案。如果我在任何时候都不清楚,请告诉我。

2 个答案:

答案 0 :(得分:3)

  1. 我认为暴露构造函数,或使用构建器或工厂模式是这里唯一的可能性。但是,下一个答案可以减轻这种情况。

  2. 为什么不将函数传递给处理解析的节点,而不是将parse方法作为抽象?

  3. public class Node<T> {
        private T defaultValue;
        private Function<String, T> parser;
    
        public Node(T defaultValue,
                    Function<String, T> parser) {
            this.defaultValue = defaultValue;
            this.parser = parser;
        }
    
        public T getValue()
        {
            // depending on the parser, re-parsing every time this is called could get expensive!
            try
            {
                // here will be some logic to get String value from some db or any other source
                String input = "true";
                return parser.apply(input);
            } catch (Exception e) {
                return defaultValue;
            }
        }
    }
    

    您现在可以通过执行此操作来创建节点

    Node<Boolean> node = new Node<>(s -> Boolean.parseBoolean(s))
    

    您还可以在解析器函数中设置默认值,无需将其存储在节点中 - 这取决于您的要求。

    1. 见2.
    2. 修改 我在这里使用Java 8的Function接口和lambdas,但您可以通过定义自己的Function接口在Java 1.0中轻松完成此操作。

      public interface Function<I, O> {
          O apply(I);
      }
      

      然后以某种方式实现它 - 具体类,匿名类等 - 根据您需要进行的解析所需。

      Node<Boolean> node = new Node<>(new Function<String, Boolean>() {
          public Boolean apply(String s) {
              return Boolean.parseBoolean(s);
          }
      });
      

      编辑2

      在回复有关预定义类型的评论时,您可以采取一些不同的方法。

      public class NodeFactory {
          private static final Function <String, Boolean> BOOLEAN_PARSER = s -> Boolean.parseBoolean(s);
          .// plus more for integers, double, etc, as required
      
          private NodeFactory() {
              // no-op
          } 
      
          public static Node<Boolean> booleanNode(boolean defaultValue){
              return new Node<Boolean>(defaultValue,
                                       BOOLEAN_PARSER);
          }
      
          // plus more for integer, double, etc, as required
      }
      

      或者你可以采取延伸路线

      public class BooleanNode extends Node<Boolean> {
          public BooleanNode(boolean defaultValue) {
              super(defaultValue,
                    s -> Boolean.parseBoolean(s)); // or use a static parser as in the factory example
          }
      }
      

      在任何情况下,保持Node非抽象可以为您的用户提供很大的灵活性,但您的用例可能不需要。

答案 1 :(得分:0)

您是否需要延长Node课程?或者只是简单地创建一个匿名类?它实际上是允许用户定义解析方法&#34;

Node<Boolean> booleanNode = new Node<Boolean>(true) {
    @Override
    protected Boolean parse(String input) {
        return Boolean.parseBoolean(input);
    }
};

也许我们可以有一个Factory类来提供这些Node类:

class NodeFactory {
    public <T> static createNode(Class<T> classType) {
        if (classType == Boolean.class) {
            return newBooleanNode();
        } else if (classType == Integer.class){
            return newIntegerNode();
        }
    } 

    private Node<Boolean> newBooleanNode() {
        return new Node<Boolean>(true) {
            @Override
            protected Boolean parse(String input) {
                return Boolean.parseBoolean(input);
            }
        }
    }

    private Node<Integer> newIntegerNode() {
        return new Node<Integer>(0) {
            @Override
            protected Boolean parse(String input) {
                return Integer.parseInt(input);
            }
        }
    }
}

在客户端,我们将有以下

Node<Boolean> booleanNode = NodeFactory.createNode(Boolean.class);
Node<Integer> integerNode = NodeFactory.createNode(Integer.class);