英文:
How to use 2 classes having same methods but without a parent class?
问题
假设我们在Java 8中有2个类,ClassA和ClassB。ClassA是一个依赖类,不能以任何方式进行更改。ClassB在某种程度上类似于ClassA,但进行了一些修改。ClassB不能扩展ClassA,但几乎具有与ClassA完全相同的功能。
public class ClassB {
public ClassB(...) {}
public int update(...) {}
public String query(...) {}
.
.
.
}
所以上述结构在ClassA中也类似存在。
假设我想编写另外两个类,ClassC使用ClassA的实例,ClassD使用ClassB的实例。ClassC和ClassD的代码完全相同,只有ClassA和ClassB的实例不同。
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。
有没有办法避免代码重复?是否可以通过某种方式编写大部分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();
}
.
.
.
}
这是解决问题的最佳方法吗?是否有更适合的方法?
英文:
Let's assume we have 2 classes in Java 8, ClassA and ClassB. ClassA is a dependency class which cannot be changed in any way. ClassB is kind of like a copy of ClassA but with some modifications. ClassB cannot extend ClassA, but has almost the exact same functions as ClassA.
public class ClassB {
public ClassB(...) {}
public int update(...) {}
public String query(...) {}
.
.
.
}
So the above structure is similarly present in ClassA as well.
Say I want to code 2 other classes ClassC that uses an instance of ClassA and ClassD that uses an instance of ClassB. ClassC and ClassD have the exact same code except for the instances of ClassA and ClassB.
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(...);
}
.
.
.
}
From the examples, it can be seen that ClassC and ClassD have the same functions but use a different Class for tmp
Is there any way that code duplication can be avoided? Can there be some way that I can write most of the functions of ClassC and ClassD as generic code and then have ClassC and ClassD extend this generic code?
Attempts at a solution
I tried a way that basically creates an interface class in a weird way. I define a ClassE that creates abstractions of ClassA and ClassB functions and also implements all the functions of ClassC and ClassD
public abstract class ClassE {
public ClassE(...) {}
public abstract int update(...);
public abstract String query(...);
public void doSomething(...) {
tmp.update(...);
tmp.query(...);
}
.
.
.
}
Then basically, ClassC and ClassD extend 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()
}
.
.
.
}
Is this the best approach to the problem? Can there be a more suitable approach?
答案1
得分: 2
你可以创建一个接口,而不是抽象类。一个通用的接口,代码如下:
public interface 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<G> tmp;
public ClassC(ClassE<G> 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);
英文:
you could create an interface, not an abstract class. A generic interface. It would be as follows:
public interface class ClassE <G> {
int update(G attr);
String query(G attr);
void doSomething(G attr);
}
You must create the class implements:
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){
.
.
.
}
}
In class c, interfaces could be used. In ClassC
, you could use the interfaces, so you pass the instance of the type you need, be it the implementation of ClassA
or 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)
}
.
.
.
}
Ex,:
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);
答案2
得分: 0
脑海中浮现的是领域驱动设计中所称的防腐层。
意思是:你在想要与之分离的部分周围创建一个抽象层,你的代码仅使用你自己的抽象。
在你的情况下:
- 你创建某个包含类C和D想要使用的功能的接口
- 你创建了该接口的两个实现,一个使用类A对象,另一个从类B对象中获取其功能
现在,你只需要将相应的实现类传递给类C和D。它们仅依赖于你的接口,因此你可以随意根据需要对它们进行重构。
请注意:在这里创建你自己的接口是最佳解决方案。你的类A和B之间没有任何“类型”关系。因此,泛型在这里没有任何帮助。
我认为你可能希望得到一个称为“鸭子类型”的东西。这是其他语言中的一个概念,你可以说“成为一只鸭子意味着:它可以quack()和walk()”例如。这意味着:当两个不同的类共享某些方法时,你可以有一个“视图”,定义一个具有这些方法的类型,这两个类都是该“视图类型”。但是Java不支持这一点(顺便说一下,Scala支持),而泛型对此无助。
英文:
What comes to mind here is what domain driven design calls an anti corruption layer.
Meaning: you create an abstraction around the parts you want to separate yourself from, and your code only uses your own abstractions
In your case:
- You create some interface that contains the functionality your classes C and D will want to use
- you create two implementations of that interface, one using a class A object, the other one derives its functionality from a class B object
Now your classes C and D just need to be passed the corresponding impl classes. They rely on your interface only, so you are free to refactor them as you find useful.
And note: creating your own interface is the best solution here. Your classes A and B do not have any "type" relationship. Therefore generics aren't of any help here.
I think you are probably hoping for something that is called "duck typing". That is a concept from other languages, where you say "being a duck means: it can quack() and it can walk()" for example. That would mean: when two different classes share certain methods, you can have a "view" that defines a type that has these methods, and both these classes are of that "view type". But java doesn't support that (scala does, btw), and generics don't help with that.
答案3
得分: 0
你可以为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(...);
}
// ... 其他共同的委托方法。
}
然后你可以使用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(...);
}
.
.
.
}
这不是一个特别好的解决方案,但它能够实现目标。
英文:
You can create a delegate class for ClassA and 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.
}
And then you can instantinate this class either with ClassA or ClassB, so from that point you can use the delegate class in your code, like this:
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(...);
}
.
.
.
}
It's not an exceptionally nice solution but it does the trick.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论