尝试用 Java 构建可扩展的数据对象和适配器模式

发布于 2024-12-15 01:07:56 字数 1191 浏览 2 评论 0原文

我正在尝试使用适配器模式构建 SDK。这是我到目前为止所得到的:

interface Adapter<T> {
  void doWork(WorkUnit<T> unit);
  Class<T> getT();
}

class WorkUnit<T> {
  public int getId() { ... }
  public T getExtras() { ... }
}

class OldWorkUnit {
  public <T> void setExtra(T data) { /* Store data in Map<Class, Object> */ }
  public <T> WorkUnit<T> toNewWorkUnit(Adapter<T> adapter) { /* Map.get(adapter.getT()) */ }
}

那里有大量的泛型,但我在编译时无法知道 T,并且可能有多个适配器,所有适配器都具有不同类型的 T。这是要暴露给第三方,所以我在接口实现中也需要尽可能少的实现,并且它必须是一个接口(没有抽象类)。

现在我想用它来调用 doWork 和 WorkUnit。我的第一遍代码如下所示:

class FooAdapter implements Adapter<FooWorkUnit> {
  ...
}

OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);

a.doWork(unit);

呃哦,这无法编译:

The method doWork(WorkUnit<capture#2-of ?>) in the type Adapter<capture#2-of ?> 
is not applicable for the arguments (WorkUnit<capture#4-of ?>)

我知道 WorkUnit 泛型参数与 Adapter.doWork() 泛型参数的类型相同,但不知道我无法转换的类型适当地。

那么有什么办法可以解决这个问题吗?

I'm trying to build an SDK using an adapter pattern. Here's what I've got so far:

interface Adapter<T> {
  void doWork(WorkUnit<T> unit);
  Class<T> getT();
}

class WorkUnit<T> {
  public int getId() { ... }
  public T getExtras() { ... }
}

class OldWorkUnit {
  public <T> void setExtra(T data) { /* Store data in Map<Class, Object> */ }
  public <T> WorkUnit<T> toNewWorkUnit(Adapter<T> adapter) { /* Map.get(adapter.getT()) */ }
}

There's a good amount of generics in there, but I can't know T at compile time, and there may be multiple Adapters, all with different types of T. This is meant to be exposed to third parties, so I also need as little implementation as possible in the interface implementation, and it has to be an interface (no abstract class).

Now I want to take this and call doWork with a WorkUnit. My first pass at the code looks like this:

class FooAdapter implements Adapter<FooWorkUnit> {
  ...
}

OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);

a.doWork(unit);

Uh oh, that doesn't compile:

The method doWork(WorkUnit<capture#2-of ?>) in the type Adapter<capture#2-of ?> 
is not applicable for the arguments (WorkUnit<capture#4-of ?>)

I know that the WorkUnit generic argument is the same type as the Adapter.doWork() generic argument, but without knowing the type I can't cast it appropriately.

So is there a way to work my way through this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨后咖啡店 2024-12-22 01:07:56

为什么你在这里使用通配符模板类?:

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);

如果你这样做:

Adapter<FooWorkUnit> a = new FooAdapter();
WorkUnit<FooWorkUnit> unit = w.toNewWorkUnit(a);

这不会保留你需要的东西吗?

现在编译器知道 FooWorkUnit 是公分母,可以这么说。

编辑:关于运行时可变性的观点是正确的。如何对执行该工作的方法进行强类型化,以便消除通配符,但仍然保持一致:

@SuppressWarnings("unchecked")
public <X> void prepareArgsAndDoTheWork() {
    OldWorkUnit w = new OldWorkUnit();
    w.setExtra(new FooWorkUnit());

    Adapter<X> a = (Adapter<X>) ... ; // Obtain the Adapter by reflection etc 
    WorkUnit<X> unit = w.toNewWorkUnit(a);
    a.doWork(unit);
}

Why do you wildcard the template class here?:

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);

If you do this:

Adapter<FooWorkUnit> a = new FooAdapter();
WorkUnit<FooWorkUnit> unit = w.toNewWorkUnit(a);

Doesn't that preserve what you need?

Now the compiler knows that FooWorkUnit is the common denominator, so to speak.

Edit: OK point taken about the runtime variability. How about strongly-typing the method that does the work, so that the wildcards are eliminated, but still consistent:

@SuppressWarnings("unchecked")
public <X> void prepareArgsAndDoTheWork() {
    OldWorkUnit w = new OldWorkUnit();
    w.setExtra(new FooWorkUnit());

    Adapter<X> a = (Adapter<X>) ... ; // Obtain the Adapter by reflection etc 
    WorkUnit<X> unit = w.toNewWorkUnit(a);
    a.doWork(unit);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文