我有两个共享一些属性和行为的类。一个这样的共同行为集群是3D空间中的操纵。因此,每个实现接口Transformable
:
public interface Transformable {
public void position (double x, double y, double z);
public void position (Tuple3d tuple);
public void rotateDeg (double yaw, double pitch, double roll);
public void rotateRad (double yaw, double pitch, double roll);
// And so on...
}
public class Foo extends Apple implements Transformable { // Foo happens }
public class Bar extends Orange implements Transformable { // Bar happens }
现在,Transformable
中每个方法的行为对于任何实现类都是相同的,并且所需的代码是实质性的。
Foo
和Bar
各自扩展了我无法控制的不同超类,并且Java没有多重继承,因此该选项已经用完。
将一大堆代码复制粘贴到实现Transformable
的每个类中,这与所有编程都是对立的。
我能够想到的最好的解决方案是创建一个包含所有实现细节的类,并使用传递方法:
public Foo extends Apple implements Transformable {
// This class has all of the repeated implementation code
private TransformationHelper helper;
public final void rotate (double yaw, double pitch, double roll) {
helper.rotate(yaw, pitch, roll);
}
}
但是,这只比重复每个类中的代码要好一些。虽然实际的实现代码在一个地方,但这仍然非常笨拙。
有没有人有更好的方法解决这个问题?
编辑:为了澄清,我确实可以控制Transformable
。整个想法是:Foo
和Bar
完全不同。它可以很容易地Shoe
和SpaceShuttle
,但两者都存在于3D空间的不同位置,并且需要一个.position(x,y,z)
方法来执行完全相同的操作。
答案 0 :(得分:4)
另一种选择,可能适用于您的情况,也可能不适用:考虑Iterator
/ Iterable
关系。一个类可以继承Iterator
实现,而不会自己扩展继承代码的类。
在您的上下文中,Transformable
会有一种方法:
interface Transformable {
Transformer getTransformer();
}
需要转换由Foo
引用的foo
的调用方将使用foo.getTransformer()
获取Transformer
,然后调用其方法进行转换。< / p>
Transformer实现将扩展包含大部分代码的抽象类,但是具有获取和设置周围对象的实际数字的抽象方法。
答案 1 :(得分:3)
您的解决方案对Java完全有效。您实际上正在使用设计模式Use Composition Over Inheritance。
正如@Naruto_Biju_Mode在评论中所说,如果您使用的是Java 8,则可以将实现移动到Transformable
的默认方法,但是您必须使辅助类具有静态方法,因为您不能在接口
interface Transformable {
default void rotate (double yaw, double pitch, double roll) {
TransformationHelper.rotate(yaw, pitch, roll);
}
...
}
或者您可以将完整实现放在默认方法中,而不是帮助程序类。这取决于你是否需要在其他地方使用这些方法
interface Transformable {
default void rotate (double yaw, double pitch, double roll) {
//actual implementation without helper class
}
...
}
无论哪种方式,如果你使用默认方法,你只需要覆盖,如果你想使用不同的实现
答案 2 :(得分:0)
(仅供参考考虑删除我的帖子标题为“继承不是选项”)
你基本上首先要创建一个抽象的超类,比方说AbstractFruit
,你仍然可以选择实现Transformable
public abstract class AbstractFruit implements Transformable {
@Override
public void position (double x, double y, double z) {
// provide implementation
}
@Override
public final void rotate (double yaw, double pitch, double roll) {
// provide implementation
}
}
然后你可以让你的水果扩展这个抽象的超级班。
答案 3 :(得分:-2)
public interface Transformable {
public void position (double x, double y, double z);
public void position (Tuple3d tuple);
public void rotateDeg (double yaw, double pitch, double roll);
public void rotateRad (double yaw, double pitch, double roll);
// And so on...
}
public class ConcreteTransformable implements Transformable {
//implement a concrete class here, you can even put your helper methods in here
public void position (double x, double y, double z) {
}
public void position (Tuple3d tuple) {
}
public void rotateDeg (double yaw, double pitch, double roll) {
};
public void rotateRad (double yaw, double pitch, double roll) {
};
}
public Foo extends Apple implements Transformable {
private Transformable transform = new ConcreteTransformable();
//if your orange needs another transform than the standard, just pass the transformable via constructor
public Apple(Transformable transform) {
this.transform = transform;
}
public void position (double x, double y, double z) {
transform.position(x,y,z);
}
public void position (Tuple3d tuple) {
transform.position(tuple);
}
//other methods also delegate to the transformable
}