问题描述
假设我们在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(...);
}
.
.
.
}
这不是一个非常好的解决方案,但是可以解决问题。
,您能否阐明这些类是什么类?是只有方法的类吗?如果是这样,两个类的方法是否执行相同的任务?还是属性的类别相同?