1

很抱歉,我无法更深入或更抽象地描述我的问题。我觉得解释我的问题的最好方法是通过这个非常具体的例子。

我想定义一个函数“readCollection”,它会解析一个字符串,并根据我调用函数的方式给我一个特定类型的特定集合。

例如,我想这样使用它:

ArrayList<Foo> fb = readCollection("Foo1\n Foo2\n Foo3\n");

或者

LinkedList<Bar> fb = readCollection("Bar1\n Bar2\n Bar3\n");

当然,我已经为每个类定义了一个接口,该接口具有用于读取一个实例(“Bar..”)的“读取”方法。

我陷入了两个问题之间:

- 自然函数 readCollection 应该是静态函数,但接口不能有静态方法。

- 方法 readCollection 应该返回 Foo 或 Bar 等类型的新对象,但我“无法实例化该类型”,这通常在我定义 readCollection 的类中定义。

- 假设该方法不是静态定义的,我不能在不引用该类型的特定对象的情况下调用它,由于前一点我不能这样做。

如何编写我的方法而不为每个 Foo 和 Bar 等复制它?

我似乎自己找到了解决方案,但它非常丑陋和讨厌。

我现在有

public interface Readable<T> {
    public T read(String str); }

public class ReadCollection<T extends Readable<T>> {
    public Collection<T> read(File file, Collection<T> ts, T t) {
        ...
        ts.add(t.read(strLine));
        ...
        return ts; 
} }

public class Bars extends ReadCollection<Bar>{
    ...
    public static void main(String[] args) {
    new Bars().read(new File("fake/path"), new ArrayList<Bar>(), new Bar()); }

在这里,我发送了一个 ArrayList 的新实例,以将结果返回给 Bar,以便引用方法“读取”。我看不出我怎么能避免这种情况。

请告诉我有更好的方法。在某个地方,我希望我事后感到非常愚蠢。

4

3 回答 3

2

考虑将解析/构造与对象本身分开。在许多情况下,这两者是非常不同的关注点。

你走在正确的轨道上,但我建议:

  1. 不要让你的元素类型从Readable接口继承
  2. Readable将接口重命名为Reader
  3. Reader为您要解析的每种类型 实现一个。
  4. 更新方法的签名ReadCollection.read以采用 aReader而不是 aT

然后,您将拥有:

public class ReadCollection<T,C extends Collection<T>> {
    public C read(File file, C ts, Reader<T> reader) {
        ...
        ts.add(reader.read(strLine));
        ...
        return ts; 
    } 
}

这为您提供了一个很好的关注点分离,应该可以解决您列出的所有问题。

于 2013-01-09T22:58:58.203 回答
1

API 应该通过接口定义。

共享实现应该通过抽象基类。

那么如何使用抽象基类而不失去接口的好处呢?

简单的!只需让抽象基类实现接口即可。

然后任何需要共享功能的类都可以扩展抽象基类,但您不必将自己束缚在任何特定的实现中,例如,这对于编写单元测试将很方便。

于 2013-01-09T22:53:59.913 回答
0

我很高兴能够告诉您,在您的评论 (@stevevls) 和朋友的帮助下,我自己找到了最终和最佳答案。

我现在有

public interface Reader {
    public Reader read(String str); }

所以我删除了通用参数,shich 是不必要的

public class ReadCollection { // no generic class!
public static <R extends Reader, C extends Collection<R>> // generic static function! 
        C readColl(File file, Class<? extends C> collClass, Class<? extends R> readClass) {
    C ts = collClass.newInstance()
        Reader t = readClass.newInstance()
        ...
        ts.add(readClass.cast(t.read(strLine)));
        ...
        return ts; 
} }

而且,现在我可以从任何地方调用该函数:

ArrayList<Point> l = ReadCollection.readColl(new File("examples/ex1.csv"), ArrayList.class, Point.class);

(假设 Point 实现 Reader / 具有读取方法...)

无需发送新实例,更重要的是:无需在任何地方扩展 ReadCollection 类。

读取方法不能是静态的,导致它在接口Reader中定义的问题仍然存在。这就是我使用 readClass.newInstance() 等的原因。

我仍然认为这个解决方案不再那么难看。

你们同意这是一个好的解决方案吗?

于 2013-01-10T13:12:01.807 回答