如何使用2个具有相同方法但没有父类的类?

问题描述

假设我们在Java 8,ClassA和ClassB中有2个类。 ClassA是一个依赖项类,不能以任何方式更改。 ClassB有点像ClassA的副本,但有一些修改。 ClassB无法扩展ClassA,但功能几乎与ClassA完全相同。

public class ClassB {
    public ClassB(...) {}
    public int update(...) {}
    public String query(...) {}
    .
    .
    .
}

因此,上述结构在ClassA中同样存在。

说我想对其他两个使用ClassA实例的类ClassC和使用ClassB实例的ClassD进行编码。除了ClassA和ClassB的实例外,ClassC和ClassD的代码完全相同。

public class ClassC {
    ClassA tmp;
    public ClassC(...) {
        tmp = new ClassA(...);
    }
    public void doSomething(...) {
        tmp.update(...);
        tmp.query(...);
    }
    .
    .
    .
}
public class ClassD {
    ClassB tmp;
    public ClassD(...) {
        tmp = new ClassB(...);
    }
    public void doSomething(...) {
        tmp.update(...);
        tmp.query(...);
    }
    .
    .
    .
}

从示例中可以看出,ClassC和ClassD具有相同的功能,但对tmp使用不同的Class

有什么办法可以避免代码重复?可以通过某种方式将ClassC和ClassD的大多数功能编写为通用代码,然后让ClassC和ClassD扩展此通用代码吗?

尝试解决方

我尝试了一种基本上以怪异的方式创建接口类的方法。我定义了一个ClassE,该类创建ClassA和ClassB函数的抽象,并实现ClassC和ClassD的所有功能

public abstract class ClassE {
    public ClassE(...) {}
    public abstract int update(...);
    public abstract String query(...);
    public void doSomething(...) {
        tmp.update(...);
        tmp.query(...);
    }
    .
    .
    .
}

然后基本上,ClassC和ClassD扩展了ClassE

public class ClassC extends ClassE {
    ClassA tmp;
    public ClassC(...) {
        tmp = new ClassA(...);
    }
    public int update(...) {
        return tmp.update(...);
    }
    public String query(...) {
        return tmp.query()
    }
    .
    .
    .
}
public class ClassD extends ClassE {
    ClassB tmp;
    public ClassD(...) {
        tmp = new ClassB(...);
    }
    public int update(...) {
        return tmp.update(...);
    }
    public String query(...) {
        return tmp.query()
    }
    .
    .
    .
}

这是解决问题的最佳方法吗?有没有更合适的方法

解决方法

您可以创建一个接口,而不是抽象类。通用接口。如下:

public interface class ClassE <G> {
     int update(G attr);
     String query(G attr);
     void doSomething(G attr);
    
 }

您必须创建类实现:

public class  ImplementClassA implements ClassE<ClassA> {

  public  int update(ClassA attr){
  .
  .
  .
  }
  public  String query(ClassA attr){
  .
  .
  .
  }
  public void doSomething(ClassA attr){
  .
  .
  .
  }
  
}  



public class  ImplementClassB implements ClassE<ClassB> {

  public  int update(ClassB attr){
  .
  .
  .
  }
  public  String query(ClassB attr){
  .
  .
  .
  }
  public void doSomething(ClassB attr){
  .
  .
  .
  }
  
}

在类c中,可以使用接口。在ClassC中,您可以使用接口,以便传递所需类型的实例,无论是ClassA 还是ClassB

的实现
public class ClassC <G> {

    private ClassE tmp;


    public ClassC(ClassE tmp) {
        this.tmp = tmp;
    }
    public int update(G attr) {
        return tmp.update(attr);
    }
    public String query(G attr) {
        return tmp.query(attr)
    }
    .
    .
    .

}

例如,

ClassC<ClassA> teste = new ClassC<ClassA>(new ImplementClassA());
ClassA save = new ClassA();
teste.update(save);
ClassC<ClassB> teste2 = new ClassC<ClassB>(new ImplementClassB());
ClassB save2 = new ClassB();
teste2.update(save2);
,

这里想到的是域驱动设计称为反腐败层

含义:您在要与自己分开的部分周围创建抽象,并且代码仅使用您的 own 抽象

在您的情况下:

  • 您创建一些接口,其中包含您的类C和D将要使用的功能
  • 您创建该接口的两种实现,一种使用A类对象,另一种从B类对象获取其功能

现在,只需将您的类C和D传递给相应的impl类即可。它们仅依赖您的接口,因此您可以在发现有用的时候随意重构它们。

注意:在这里,创建自己的界面是最佳解决方案。您的A类和B类没有任何“类型”关系。因此,泛型在这里没有任何帮助。

我认为您可能希望找到一种叫做“鸭子打字”的东西。例如,这是来自其他语言的一个概念,在这里您说“成为鸭子意味着:它可以发出quack()并且可以发出walk()”。这意味着:当两个不同的类共享某些方法时,您可以拥有一个“视图”,该视图定义具有这些方法的类型,并且这两个类都属于该“视图类型”。但是java不支持(顺便说一句,scala支持),而泛型则无济于事。

,

您可以为ClassA和ClassB创建委托类:

public class delegateAB {
  private ClassA a;
  private ClassB b;

  public delegateAB(ClassA a) {
    this.a = a;
  }

  public delegateAB(ClassB b) {
    this.b = b;
  }

  public int update(...) {
    return a!=null?a.update(...):b.update(...)
  }

  // ... other common delegated methods.
}

然后您可以使用ClassA或ClassB实例化此类,因此从那时起,您可以在代码中使用委托类,如下所示:

public class ClassCD {
    DelegateAB tmp;

    public ClassCD(ClassA a,...) {
        tmp = new DelegateAB(a);
    }

    public ClassCD(ClassB b,...) {
        tmp = new DelegateAB(b);
    }

    public void doSomething(...) {
        tmp.update(...);
        tmp.query(...);
    }
    .
    .
    .
}

这不是一个非常好的解决方案,但是可以解决问题。

,

您能否阐明这些类是什么类?是只有方法的类吗?如果是这样,两个类的方法是否执行相同的任务?还是属性的类别相同?