如何用相同的方法“包装”两个类?

我必须使用相同的方法处理两个类,但它们不实现相同的接口,也不扩展相同的超类。 我不能/不允许更改这个类,我不构造这个类的实例我只得到这个对象。 避免大量代码重复的最佳方法是什么?

其中一个类:

package faa; public class SomethingA { private String valueOne = null; private String valueTwo = null; public String getValueOne() { return valueOne; } public void setValueOne(String valueOne) { this.valueOne = valueOne; } public String getValueTwo() { return valueTwo; } public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; } } 

和另外一个…

 package foo; public class SomethingB { private String valueOne; private String valueTwo; public String getValueOne() { return valueOne; } public void setValueOne(String valueOne) { this.valueOne = valueOne; } public String getValueTwo() { return valueTwo; } public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; } } 

(实际上这些类更大)

我唯一的想法是在这里创建一个包装类:

 public class SomethingWrapper { private SomethingA someA; private SomethingB someB; public SomethingWrapper(SomethingA someA) { //null check.. this.someA = someA; } public SomethingWrapper(SomethingB someB) { //null check.. this.someB = someB; } public String getValueOne() { if (this.someA != null) { return this.someA.getValueOne(); } else { return this.someB.getValueOne(); } } public void setValueOne(String valueOne) { if (this.someA != null) { this.someA.setValueOne(valueOne); } else { this.someB.setValueOne(valueOne); } } public String getValueTwo() { if (this.someA != null) { return this.someA.getValueTwo(); } else { return this.someB.getValueTwo(); } } public void setValueTwo(String valueTwo) { if (this.someA != null) { this.someA.setValueTwo(valueTwo); } else { this.someB.setValueTwo(valueTwo); } } } 

但我对此解决方案并不满意。 有没有更好/更优雅的方法来解决这个问题?

一个更好的解决方案是创建一个接口来表示两个类的统一接口,然后编写两个实现接口的类,一个包装A,另一个包装B:

 public interface SomethingWrapper { public String getValueOne(); public void setValueOne(String valueOne); public String getValueTwo(); public void setValueTwo(String valueTwo); }; public class SomethingAWrapper implements SomethingWrapper { private SomethingA someA; public SomethingWrapper(SomethingA someA) { this.someA = someA; } public String getValueOne() { return this.someA.getValueOne(); } public void setValueOne(String valueOne) { this.someA.setValueOne(valueOne); } public String getValueTwo() { return this.someA.getValueTwo(); } public void setValueTwo(String valueTwo) { this.someA.setValueTwo(valueTwo); } }; 

然后另一个类就像SomethingBWrapper一样。

在那里,鸭子型解决方案。 这将接受具有valueOnevalueTwo属性的任何对象,并且可以简单地扩展为进一步的道具。

 public class Wrapper { private final Object wrapped; private final Map methods = new HashMap(); public Wrapper(Object w) { wrapped = w; try { final Class c = w.getClass(); for (String propName : new String[] { "ValueOne", "ValueTwo" }) { final String getter = "get" + propName, setter = "set" + propName; methods.put(getter, c.getMethod(getter)); methods.put(setter, c.getMethod(setter, String.class)); } } catch (Exception e) { throw new RuntimeException(e); } } public String getValueOne() { try { return (String)methods.get("getValueOne").invoke(wrapped); } catch (Exception e) { throw new RuntimeException(e); } } public void setValueOne(String v) { try { methods.get("setValueOne").invoke(wrapped, v); } catch (Exception e) { throw new RuntimeException(e); } } public String getValueTwo() { try { return (String)methods.get("getValueTwo").invoke(wrapped); } catch (Exception e) { throw new RuntimeException(e); } } public void setValueTwo(String v) { try { methods.get("setValueTwo").invoke(wrapped, v); } catch (Exception e) { throw new RuntimeException(e); } } } 

您可以使用动态代理在您定义的接口和符合但未实现接口的类之间创建“桥接”。

一切都从界面开始:

 interface Something { public String getValueOne(); public void setValueOne(String valueOne); public String getValueTwo(); public void setValueTwo(String valueTwo); } 

现在你需要一个InvocationHandler ,它只是将调用转发InvocationHandler的接口方法匹配的方法:

 class ForwardInvocationHandler implements InvocationHandler { private final Object wrapped; public ForwardInvocationHandler(Object wrapped) { this.wrapped = wrapped; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes()); return match.invoke(wrapped, args); } } 

然后,您可以创建代理(将其放在工厂中以便于使用):

 SomethingA a = new SomethingA(); a.setValueOne("Um"); Something s = (Something)Proxy.newProxyInstance( Something.class.getClassLoader(), new Class[] { Something.class }, new ForwardInvocationHandler(a)); System.out.println(s.getValueOne()); // prints: Um 

另一个选项更简单但需要您子类化每个类并实现创建的接口,就像这样:

 class SomethingAImpl extends SomethingA implements Something {} class SomethingBImpl extends SomethingB implements Something {} 

(注意:您还需要创建任何非默认构造函数)

现在使用子类而不是超类,并通过接口引用它们:

 Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl o.setValueOne("Uno"); System.out.println(o.getValueOne()); // prints: Uno 

我认为你原来的包装类是最可行的选择…但它可以使用reflection来完成,你真正的问题是应用程序是一个烂摊子…reflection可能不是你正在寻找的方法

我有另一个提议,可能会有所帮助:创建一个包装类,它具有针对每种类型的特定函数…它主要是copypaste,但它会强制您使用类型化的东西作为参数

 class X{ public int asd() {return 0;} } class Y{ public int asd() {return 1;} } class H{ public int asd(X a){ return a.asd(); } public int asd(Y a){ return a.asd(); } } 

用法:

 System.out.println("asd"+h.asd(x)); System.out.println("asd"+h.asd(y)); 

我想要注意,一个接口也可以由祖先实现,如果你正在创建这些类 – 但是不能修改它的源,那么你仍然可以从外部重载它们:

 public interface II{ public int asd(); } class XI extends X implements II{ } class YI extends Y implements II{ } 

用法:

 II a=new XI(); System.out.println("asd"+a.asd()); 

您可能可以利用外观和reflection – 我认为它简化了您访问遗产的方式,并且可以扩展!

 class facade{ public static getSomething(Object AorB){ Class c = AorB.getClass(); Method m = c.getMethod("getValueOne"); m.invoke(AorB); } ... } 

我写了一个类来封装日志框架API。 不幸的是,放入这个盒子太长了。

该程序是http://www.github.com/bradleyross/tutorials项目的一部分,其文档位于http://bradleyross.github.io/tutorials 。 模块教程中常见的类bradleyross.library.helpers.ExceptionHelper的代码位于https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/ helpers / ExceptionHelper.java 。

我的想法是,我可以使用其他代码来使exception语句更有用,我不必为每个日志框架重复它们。 包装器不是您消除代码重复的地方。 消除代码重复不需要编写调用包装器和底层类的代码的多个版本。 请参阅https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/

类bradleyross.helpers.GenericPrinter是另一个包装器,它使您能够编写适用于PrintStream,PrintWriter和StringWriter类和接口的代码。