可以从我的代码中重构另一个包中的 Java 接口吗?

发布于 2024-11-28 19:06:18 字数 402 浏览 4 评论 0原文

我在我的 Java 项目中使用(开源)API 并从中引用接口。一个接口 (Foo) 在 API 和使用它的项目中广泛使用。对于我的项目,我想使用一个仅公开 Foo 所执行的方法的子集的接口,这样 Foo 将从我的新接口继承方法(<代码>条)。我根本不想改变 Foo 的界面;相反,我希望能够编写实现 Bar 的类,然后将它们与实现 Foo 的类一起操作,就好像它们都是 Bar< /代码>。

由于 API 位于不同的包中,是否有任何方法可以实现此目的,使 Bar 成为所有 Foo 的超类(接口)?

I'm using an (open-source) API in my Java project and referencing interfaces from it. One interface (Foo) is used extensively both in the API and in projects that use it. For my project, I'd like to use an interface which only exposes a subset of the methods that Foo does, such that Foo would inherit methods from my new interface (Bar). I don't want to change the interface of Foo at all; rather, I'd like to be able to write classes which implement Bar, and then manipulate those along with classes which implement Foo as if they are all Bar.

Since the API is in a different package, is there any way to accomplish this such that Bar is a superclass (interface) of all Foo?

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

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

发布评论

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

评论(4

苄①跕圉湢 2024-12-05 19:06:18

我希望能够编写实现 Bar 的类,然后
与实现 Foo 的类一起操作它们,就像它们一样
所有酒吧。

您可以创建一个实现 Foo 的抽象 Bar。您将放弃两者共享的方法并实现 Bar 不共享的方法,这样它们就会抛出 UnsupportedOperationException 之类的异常。

但是你不能像操作 Bar 一样操作 Foo;恰恰相反。您无法按照您提出的方式满足里氏替换原则。

I'd like to be able to write classes which implement Bar, and then
manipulate those along with classes which implement Foo as if they are
all Bar.

You can create an abstract Bar that implements Foo. You'll leave off the methods shared by the two and implement the methods that Bar does not share so they throw an exception like UnsupportedOperationException.

But you can't manipulate Foo as if it were Bar; it's the other way 'round. You can't satisfy the Liskov Substitution Principle the way you're proposing.

逆蝶 2024-12-05 19:06:18

您可能需要使用 Aspect 来实现这一点。看起来 AspectJ 有一个 @DeclareParents 可能会做你想做的事。

You're probably going to need to use an Aspect to make this happen. It looks like AspectJ has a @DeclareParents that might do what you want.

凡尘雨 2024-12-05 19:06:18

您可以使用 适配器模式 来完成此操作:

public class FooAdapter implements Bar {
   private Foo wrapped;
   public FooAdapter(Foo foo) {
      wrapped = foo;
   }
   public void op1() {
      foo.op1();
   }
   public string op2(int param) {
      return foo.op2(param);
   }
}

You could use the Adapter Pattern to accomplish this:

public class FooAdapter implements Bar {
   private Foo wrapped;
   public FooAdapter(Foo foo) {
      wrapped = foo;
   }
   public void op1() {
      foo.op1();
   }
   public string op2(int param) {
      return foo.op2(param);
   }
}
柠北森屋 2024-12-05 19:06:18

因为 Java 有名义类型,所以 org.theirs.Fooorg.yours.Foo 没有任何关系,即使它们具有完全相同的方法签名,我不认为 Java 中的继承可以做到这一点。即使使用泛型,据我所知,也无法说“此方法采用 Bar 的实例”。

相反,我认为您想为库的 Foo适配器接口 >,使用您自己的(即 FooAdapter,具有与 Foo 完全相同的签名)并扩展 Bar。然后可以从 FooAdapter 中提取 Bar 中所需的方法。不幸的是,您的代码必须进行修改,以便您之前引用其 Foo任何地方,您可以改为引用:

  • Bar(如果调用的唯一方法) 需要在接口 FooAdapter 中定义这些方法
  • 如果调用 Foo 中定义的方法而不是 Bar 中定义的方法,则

。这种方法虽然干净,并且很好地分离了关注点,但恐怕实施起来会很痛苦且乏味。

以下代码片段显示了其工作原理的示例:

第 3 方库

package org.theirs;
public interface Foo {
    void doSomething();
    void doSomethingExtra();
}

您的代码

package org.mine;
public interface Bar {
    void doSomething();
}

public class BarImpl implements Bar{
     public void doSomething( /* implementation */ );
}

public class FooAdapter implements Bar{
    private final Foo adapted;
    public FooAdapter(Foo adapted) {
         this.adapted = adapted;
    }
    public void doSomething() {
        adapted.doSomething(); // delegate to adapted instance
    }
}

public class UsingThoseBars {
    public void doSomethingWithAllThoseBars(Collection<Bar> bars) {
         // each entry in bars could either be a BarImpl or a FooAdapter    
    }
}

您可以从此示例中看到,方法 doSomethingExtra() 无法从您的代码访问,因为接口 < code>Bar 没有指定它。

其他建议

请注意,您可能可以在类重写方面使用一些有用的技巧,例如使用 AspectJ。我假设您更愿意在纯 Java 编译时获得您想要的效果。

另一个建议是实现 Bar ,它会为不需要的 Foo 方法抛出 UnsupportedOperationException 。尽管在主要的 Java 库中已有这样的先例(例如 JDK 中的 UnmodifyingList),但我一般建议不要采用这种做法。但是,如果用新的 FooAdapter 替换对其 Foo 的引用的成本相当高,那么使用此策略可能是一个不错的权衡。

Because Java has nominal typing, such that org.theirs.Foo is in no way related to org.yours.Foo, even if they have the exact same method signatures, I don't think this is possible to do with inheritance in Java. Even with generics, AFAIK there is no way to say, "this method takes an instance of Bar<T extends Foo OR Bar>".

Instead, I think you want to use an Adapter interface for the library's Foo, with your own (i.e. a FooAdapter, having the exact same signatures as Foo) and have this extend Bar. The methods you want in Bar could then be extracted from FooAdapter. Unfortunately your code would have to be modified so that everywhere you previously referenced their Foo, you would instead reference either:

  • Bar if the only methods called are those you would define in your interface
  • FooAdapter if methods defined in Foo but NOT in Bar are called.

This method, although clean, and a good separation of concerns, can be painful and tedious to implement, I'm afraid.

An example of how this would work is shown in the following code snippets:

3rd Party Library

package org.theirs;
public interface Foo {
    void doSomething();
    void doSomethingExtra();
}

Your code

package org.mine;
public interface Bar {
    void doSomething();
}

public class BarImpl implements Bar{
     public void doSomething( /* implementation */ );
}

public class FooAdapter implements Bar{
    private final Foo adapted;
    public FooAdapter(Foo adapted) {
         this.adapted = adapted;
    }
    public void doSomething() {
        adapted.doSomething(); // delegate to adapted instance
    }
}

public class UsingThoseBars {
    public void doSomethingWithAllThoseBars(Collection<Bar> bars) {
         // each entry in bars could either be a BarImpl or a FooAdapter    
    }
}

You can see from this example that the method doSomethingExtra() is not accessible from your code, since the interface Bar does not specify it.

Other Suggestions

Note there may be useful tricks you could do with class rewriting, such as with AspectJ. I'm assuming you'd rather have the effect you desire at compile-time, in pure Java.

Another suggestion is to have an implementation of Bar which throws UnsupportedOperationException for the methods of Foo that you don't need. Although there is a precedent for this in major Java libraries (e.g. UnmodifiableList in the JDK) I would recommend against this practice in general. However, if the cost of replacing references to their Foo with your new FooAdapter is quite high, it may be a good trade off to use this strategy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文