java 是否支持 "Soft" 接口?
Does java support "Soft" interfaces?
考虑以下场景:
假设您创建了一个接口 Foo
:
public interface Foo {
public void bar();
}
并说某库中有一个旧的classSomeOldClass
你要用。它已经有 bar()
方法,但没有显式实现 Foo
.
您已经为实现 Foo
的所有 classed 编写了以下代码:
public <T extends Foo> T callBarOnThird(List<T> fooList){
return fooList.get(2).bar();
}
现在您希望它也适用于 SomeOldClass
。您无权访问此 class 的源代码,因此无法修改它。
有没有办法声明 Foo
或类似于某种 "soft" 接口的东西,(因为任何实现所有必需方法的 class 都将被接受为软接口的隐式实现)?如果没有,您将如何使用尽可能干净的代码来解决这个问题?
不,不是。
您必须提供一个适配器实例(有多种方法和工具可以提供帮助,但 Java 不会这样做 "implicitly")。
Thilos 答案的扩展。
你也可以使用装饰器来处理这个
public <T extends Foo> T callBarOnThird(List<T> fooList){
return new BarDecorator(fooList.get(2)).bar();
}
在装饰器内部,您可以检查给定的对象是否是 Foo 的实例,然后进行相应的操作。
Java 是 静态类型 和 动态绑定 .
动态绑定: 这意味着方法签名与其实现之间的链接发生在运行时。例如。
例如
public interface MyInterface {
void doStuff();
}
public class MyFirstImpl implements MyInterface {
@Override
public void doStuff() {
// do some stuff here
}
}
public class MySecondImpl implements MyInterface {
@Override
public void doStuff() {
// do some stuff here
}
}
所以如果你想要下一个片段
MyInterface test; // pointing to either MyFirstImpl or MySecondImpl
test.doStuff();
JVM 会根据对象的运行时类型,在运行时天气决定从MyFirstImpl
或MySecondImpl
调用doStuff
方法。
静态类型: 这意味着 JVM 将在编译时检查是否有一个方法可以调用,而不管实现。
例如:
public interface MyInterface {
void doStuff();
}
public class MyFirstImpl implements MyInterface {
// no override here
public void doStuff() {
// do some stuff here
}
}
public class MySecondImpl implements MyInterface {
// no override here
public void doStuff() {
// do some stuff here
}
}
所以如果你想要下一个片段
MyInterface test; // pointing to either MyFirstImpl or MySecondImpl
test.doStuff();
编译器会抱怨,因为它无法在编译时确保无论 MyInterface
的实现如何,都有一个 doStuff
方法可以调用(尽管在这种情况下, [ 的两个实现=19=]定义一个doStuff
方法)。
这确保您不会在运行时获得 NoSuchMethodException
,例如,如果您要通过下一个实现。
public class MySecondImpl implements MyInterface {
// no override here
// no doStuff method
}
这会以一些刚性为代价为语言增加了一些类型安全性(因为您能够比在运行时更早地确定问题,因此您有一个更短的反馈循环,代价是所有的场景这些实现实际上公开了无法开箱即用的方法。
你应该如何重构你的代码:
在第三方库上创建一个包装器并从包装器公开接口。
public interface Foo {
void bar();
}
public class ThirdPartyFooWrapper implements Foo {
private SomeOldClass oldClass;
public ThordPartyFooWrapper (SomeOldClass oldClass){
this.oldClass = oldClass;
}
@Override
public void bar() {
this.oldClass.bar();
}
}
然后,在您的代码中使用 ThirdPartyFooWrapper
而不是 SomeOldClass
。
希望这能回答您的问题!
考虑以下场景:
假设您创建了一个接口 Foo
:
public interface Foo {
public void bar();
}
并说某库中有一个旧的classSomeOldClass
你要用。它已经有 bar()
方法,但没有显式实现 Foo
.
您已经为实现 Foo
的所有 classed 编写了以下代码:
public <T extends Foo> T callBarOnThird(List<T> fooList){
return fooList.get(2).bar();
}
现在您希望它也适用于 SomeOldClass
。您无权访问此 class 的源代码,因此无法修改它。
有没有办法声明 Foo
或类似于某种 "soft" 接口的东西,(因为任何实现所有必需方法的 class 都将被接受为软接口的隐式实现)?如果没有,您将如何使用尽可能干净的代码来解决这个问题?
不,不是。
您必须提供一个适配器实例(有多种方法和工具可以提供帮助,但 Java 不会这样做 "implicitly")。
Thilos 答案的扩展。
你也可以使用装饰器来处理这个
public <T extends Foo> T callBarOnThird(List<T> fooList){
return new BarDecorator(fooList.get(2)).bar();
}
在装饰器内部,您可以检查给定的对象是否是 Foo 的实例,然后进行相应的操作。
Java 是 静态类型 和 动态绑定 .
动态绑定: 这意味着方法签名与其实现之间的链接发生在运行时。例如。
例如
public interface MyInterface {
void doStuff();
}
public class MyFirstImpl implements MyInterface {
@Override
public void doStuff() {
// do some stuff here
}
}
public class MySecondImpl implements MyInterface {
@Override
public void doStuff() {
// do some stuff here
}
}
所以如果你想要下一个片段
MyInterface test; // pointing to either MyFirstImpl or MySecondImpl
test.doStuff();
JVM 会根据对象的运行时类型,在运行时天气决定从MyFirstImpl
或MySecondImpl
调用doStuff
方法。
静态类型: 这意味着 JVM 将在编译时检查是否有一个方法可以调用,而不管实现。
例如:
public interface MyInterface {
void doStuff();
}
public class MyFirstImpl implements MyInterface {
// no override here
public void doStuff() {
// do some stuff here
}
}
public class MySecondImpl implements MyInterface {
// no override here
public void doStuff() {
// do some stuff here
}
}
所以如果你想要下一个片段
MyInterface test; // pointing to either MyFirstImpl or MySecondImpl
test.doStuff();
编译器会抱怨,因为它无法在编译时确保无论 MyInterface
的实现如何,都有一个 doStuff
方法可以调用(尽管在这种情况下, [ 的两个实现=19=]定义一个doStuff
方法)。
这确保您不会在运行时获得 NoSuchMethodException
,例如,如果您要通过下一个实现。
public class MySecondImpl implements MyInterface {
// no override here
// no doStuff method
}
这会以一些刚性为代价为语言增加了一些类型安全性(因为您能够比在运行时更早地确定问题,因此您有一个更短的反馈循环,代价是所有的场景这些实现实际上公开了无法开箱即用的方法。
你应该如何重构你的代码:
在第三方库上创建一个包装器并从包装器公开接口。
public interface Foo {
void bar();
}
public class ThirdPartyFooWrapper implements Foo {
private SomeOldClass oldClass;
public ThordPartyFooWrapper (SomeOldClass oldClass){
this.oldClass = oldClass;
}
@Override
public void bar() {
this.oldClass.bar();
}
}
然后,在您的代码中使用 ThirdPartyFooWrapper
而不是 SomeOldClass
。
希望这能回答您的问题!