簡體   English   中英

如何用相同的方法“包裝”兩個類?

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

我必須使用相同的方法處理兩個類,但它們不實現相同的接口,也不擴展相同的超類。 我不能/不允許更改這個類,我不構造這個類的實例我只得到這個對象。 避免大量代碼重復的最佳方法是什么?

其中一個類:

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

您可以使用動態代理在您定義的接口和符合但未實現接口的類之間創建“橋接”。

一切都從一個界面開始:

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

我認為你原來的包裝類是最可行的選擇...但它可以使用反射來完成,你真正的問題是應用程序是一團糟......反射可能不是你要找的方法

我有另一個提議,可能會有所幫助:創建一個包裝類,它具有針對每種類型的特定函數...它主要是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());

您可能可以利用外觀和反射 - 在我看來,它簡化了您訪問遺產的方式,並且可以擴展!

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

我的想法是,我可以使用其他代碼來使異常語句更有用,我不必為每個日志框架重復它們。 包裝器不是您消除代碼重復的地方。 消除代碼重復不需要編寫調用包裝器和底層類的代碼的多個版本。 請參閱https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/

bradleyross.helpers.GenericPrinter類是另一個包裝器,它使您能夠編寫適用於PrintStream,PrintWriter和StringWriter類和接口的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM