我正在尝试在可能的情况下使用作文来扩展课程。但我遇到了一个特殊问题。
假设我有一个基类和一个扩展类。如果我们使用组合,并且希望注入依赖项,扩展类将接受基类的实例,而不是继承它:
public class Base
{
private ISomeDependency dependency;
public Base(ISomeDependency dependency)
{
this.dependency = dependency;
}
public ISomeDependency getDependency()
{
return dependency;
}
}
public class Extending
{
private Base base;
public Extending(Base base)
{
this.base = base;
}
}基类接受一些依赖项,然后我们可以使用getDependency()方法在扩展类中使用这些依赖项。
但是,如果我们想专门化扩展类中所需的的子类型,那么会怎样呢?
如果我们使用继承,我们可以简单地将子类型传递给超类构造函数,如下所示:
public class Extending extends Base
{
private ISomeDependencySubtype dependency;
public Extending(ISomeDependencySubtype dependency)
{
super(dependency);
this.dependency = dependency;
}
}但是如果我们使用作文,那么这就变得更加困难了。我想出了几种选择:
具有初始化方法,而不是基中的构造函数
public class Extending
{
private ISomeDependencySubtype dependency;
private Base base;
public Extending(Base base, ISomeDependencySubtype dependency)
{
base.init(dependency);
this.base = base;
this.dependency = dependency;
}
}该选项隐藏了这样一个事实:扩展类在基类上使用init()方法,因此接口可能变得不清晰。在使用扩展类时,另一个程序员可能会假设,在将基本实例传递到扩展实例之前,必须对其调用init()。
添加泛型参数
public class Base<T extends ISomeDependency>
{
private T dependency;
public Base(T dependency)
{
this.dependency = dependency;
}
public T getDependency()
{
return dependency;
}
}
public class Extending
{
private ISomeDependencySubtype dependency;
private Base<ISomeDependencySubtype> base;
public Extending(Base<ISomeDependencySubtype> base)
{
this.base = base;
this.dependency = base.getDependency();
}
}这似乎是滥用仿制药。如果基类本身就是一个类,并且可以在没有扩展类的情况下使用,那么它不需要关心ISomeDependency的哪个子类型被传递给它。泛型参数只存在于此特定场景中,尽管需要重构以适应它。
扩展内部的实例化库
public class Extending
{
private ISomeDependencySubtype dependency;
private Base base;
public Extending(ISomeDependencySubtype dependency)
{
this.base = new Base(dependency);
this.dependency = dependency;
}
}这意味着不能传递基本实例,这意味着不能注入依赖项。这是不灵活的原因,这可能是显而易见的大多数。
因此,我想知道人们认为使用组合来解决这个问题最可取的选择是什么(请不要基于继承的答案)。
发布于 2014-10-03 02:35:39
这和所有协变量依赖的问题一样,是一个有点病态的问题,而且可能没有完美的解决方案。
除了您的解决方案之外,还可以只将Base的类型和ISomeDependency的一个实例传递给Extending的构造函数,并动态地实例化Base对象。
public class Extending {
// Keep an additional copy (ugly and probably unsafe).
final dependendcy dependendcy;
final Base base;
public Extending(final Class<? extends Base> cls,
final ISomeDependencySubtype dependendcy) throws Exception {
this.dependency = dependency;
this.base = cls.getConstructor(ISomeDependency.class).newInstance(dependency);
}
}这有一个明显的缺点,即您必须假设一个Base的适当构造函数,这个构造函数不能由Java的类型系统静态地强制执行。
如果您愿意的话,您还可以假设一个默认的构造函数(可能看起来更简单一些),然后使用依赖项调用一个init方法。我不喜欢init方法。这样,您将消除是否应该由调用方初始化Base的模糊性。
在我看来,所有依赖于对依赖项保持额外引用的解决方案都是不安全的,因为不能保证Base不会这样替换对象。
assert this.dependency == this.base.getDependency();很可能会失败。当然,降低getDependency返回的引用并不安全,因为出于同样的原因,
assert this.base.getDependency() instanceof ISomeDependencySubtype;也可能会失败。
即使Extending extends Base (你说你不想要),这个问题也没有好转。
泛型方法可以解决这个问题,但它为您购买了所有其他类型的问题。
因为我不认为一个完美的解决方案存在,它可能在很大程度上取决于实际的用例,哪个邪恶的接受。
https://stackoverflow.com/questions/26171449
复制相似问题