简体   繁体   English

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

[英]How to 'wrap' two classes with identical methods?

I have to handle two classes with identical methods but they don't implement the same interface, nor do they extend the same superclass. 我必须使用相同的方法处理两个类,但它们不实现相同的接口,也不扩展相同的超类。 I'm not able / not allowed to change this classes and I don't construct instances of this classes I only get objects of this. 我不能/不允许更改这个类,我不构造这个类的实例我只得到这个对象。 What is the best way to avoid lots of code duplication? 避免大量代码重复的最佳方法是什么?

One of the class: 其中一个类:

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; }
}

And the other... 和另一个...

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; }
}

(In reality these classes are larger) (实际上这些类更大)

My only idea is now to create a wrapper class in this was: 我唯一的想法是在这里创建一个包装类:

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);
        }
    }
} 

But I'm not realy satisfied with this solution. 但我对此解决方案并不满意。 Is there any better / more elegant way to solve this problem? 有没有更好/更优雅的方法来解决这个问题?

A better solution would be to create an interface to represent the unified interface to both classes, then to write two classes implementing the interface, one that wraps an A, and another that wraps a B: 一个更好的解决方案是创建一个接口来表示两个类的统一接口,然后编写两个实现接口的类,一个包装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);
    }
};

and then another class just like it for SomethingBWrapper. 然后另一个类就像SomethingBWrapper一样。

There, a duck-typed solution. 在那里,鸭子型解决方案。 This will accept any object with valueOne , valueTwo properties and is trivially extensible to further props. 这将接受具有valueOnevalueTwo属性的任何对象,并且可以简单地扩展为进一步的道具。

public class Wrapper
{
  private final Object wrapped;
  private final Map<String, Method> methods = new HashMap<String, Method>();
  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); }
  }
}

You can use a dynamic proxy to create a "bridge" between an interface you define and the classes that conform but do not implement your interface. 您可以使用动态代理在您定义的接口和符合但未实现接口的类之间创建“桥接”。

It all starts with an interface: 一切都从一个界面开始:

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

Now you need an InvocationHandler , that will just forward calls to the method that matches the interface method called: 现在你需要一个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);
  }
}

Then you can create your proxy (put it in a factory for easier usage): 然后,您可以创建代理(将其放在工厂中以便于使用):

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

Another option is simpler but requires you to subclass each class and implement the created interface, simply like this: 另一个选项更简单,但要求您子类化每个类并实现创建的接口,就像这样:

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

(Note: you also need to create any non-default constructors) (注意:您还需要创建任何非默认构造函数)

Now use the subclasses instead of the superclasses, and refer to them through the interface: 现在使用子类而不是超类,并通过接口引用它们:

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

i think your original wrapper class is the most viable option...however it can be done using reflection, your real problem is that the application is a mess...and reflection is might not be the method you are looking for 我认为你原来的包装类是最可行的选择...但它可以使用反射来完成,你真正的问题是应用程序是一团糟......反射可能不是你要找的方法

i've another proposal, which might be help: create a wrapper class which has specific functions for every type of classes...it mostly copypaste, but it forces you to use the typed thing as a parameter 我有另一个提议,可能会有所帮助:创建一个包装类,它具有针对每种类型的特定函数...它主要是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();
        }
}

usage: 用法:

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

i would like to note that an interface can be implemented by the ancestor too, if you are creating these classes - but just can't modify it's source, then you can still overload them from outside: 我想要注意,一个接口也可以由祖先实现,如果你正在创建这些类 - 但是不能修改它的源,那么你仍然可以从外部重载它们:

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

usage: 用法:

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

You probably can exploit a facade along with the reflection - In my opinion it streamlines the way you access the legacy and is scalable too ! 您可能可以利用外观和反射 - 在我看来,它简化了您访问遗产的方式,并且可以扩展!

class facade{

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

}

I wrote a class to encapsulate the logging framework API's. 我编写了一个类来封装日志框架API。 Unfortunately, it's too long to put in this box. 不幸的是,放入这个盒子太长了。

The program is part of the project at http://www.github.com/bradleyross/tutorials with the documentation at http://bradleyross.github.io/tutorials . 该程序是http://www.github.com/bradleyross/tutorials项目的一部分,其文档位于http://bradleyross.github.io/tutorials The code for the class bradleyross.library.helpers.ExceptionHelper in the module tutorials-common is at https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/helpers/ExceptionHelper.java . 模块教程中常见的类bradleyross.library.helpers.ExceptionHelper的代码位于https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/ helpers / ExceptionHelper.java

The idea is that I can have the additional code that I want to make the exception statements more useful and I won't have to repeat them for each logging framework. 我的想法是,我可以使用其他代码来使异常语句更有用,我不必为每个日志框架重复它们。 The wrapper isn't where you eliminate code duplication. 包装器不是您消除代码重复的地方。 The elimination of code duplication is in not having to write multiple versions of the code that calls the wrapper and the underlying classes. 消除代码重复不需要编写调用包装器和底层类的代码的多个版本。 See https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/ 请参阅https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/

The class bradleyross.helpers.GenericPrinter is another wrapper that enables you to write code that works with both the PrintStream, PrintWriter, and StringWriter classes and interfaces. bradleyross.helpers.GenericPrinter类是另一个包装器,它使您能够编写适用于PrintStream,PrintWriter和StringWriter类和接口的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM