如何在继承不是一个选项时实现重复行为

时间:2015-06-21 00:07:49

标签: java oop interface

我有两个共享一些属性和行为的类。一个这样的共同行为集群是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中每个方法的行为对于任何实现类都是相同的,并且所需的代码是实质性的。

FooBar各自扩展了我无法控制的不同超类,并且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。整个想法是:FooBar完全不同。它可以很容易地ShoeSpaceShuttle,但两者都存在于3D空间的不同位置,并且需要一个.position(x,y,z)方法来执行完全相同的操作。

4 个答案:

答案 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

}