簡體   English   中英

關於java中虛擬方法的問題

[英]question about virtual methods in java

簡單地說:我想要以下代碼打印“sub”:

Element e = new SubElement();
print(e);
... 

private static void print(Element e) {
    System.out.println("e");
}

private static void print(SubElement e) {
    System.out.println("sub");
}

我不想改變印刷品(元素e)。 所以沒什么

private static void print(Element e) {
    if (e instanceof SubElement) {
        print((SubElement) e);
    } else {
        System.out.println("e");
    }
}

我想做的是

print(e.getClass().cast(e));

自動將其強制轉換為真正的子類並強制系統輸入print(SubElement e)。 這有點可能嗎?

在編譯時選擇運行的重載方法,這就是選擇Element版本而不是SubElement版本的原因。 更合理的是讓Element或子類包含應該打印的數據。

class Element {

    public String getName() {
        return "e";
    }
}

class SubElement extends Element {
    public String getName() {
        return "sub";
    }
}

然后在打印方法中:

private static void print(Element e) {
    System.out.println(e.getName());
}

這是否有意義將取決於Element類實際是什么以及打印數據代表什么。

是。 您可以使用訪客模式 但是它適用於穩定的定義良好的層次結構,因為您必須定義的Visitor接口需要每種類型的方法。

interface ElementVisitor {
   visit(Element e);
   visit(SubElement se);
}

class ElementerPrinter implements ElementVisitor {
   visit(Element e) { System.out.println("e"); }
   visit(SubElement e) { System.out.println("sub"); }
}

class Element {
  // here's the trick, Element knows that this is Element
  // and childs have to implement it!
  // if the parent-most class is an interface it force you to implement!
  accept(ElementVisitor visitor) { visitor.visit(this); } 
}

class SubElement {
  // here's the trick, Element knows that this is SubElement
  accept(ElementVisitor visitor) { visitor.visit(this); }
}

print()需要成為Element的實例方法。 你試圖以一種艱難的方式模仿多態。 如果你想這樣做,你無法真正避免從Class到函數對象的一些if語句映射。 何必呢?

您是否能夠將行為差異推向元素類?

Element e = new SubElement();
print(e);
... 

private static void print(Element e) {
    System.out.println(e.getMessageToPrint());
}

// no longer needed
//
//private static void print(SubElement e) {
//    System.out.println("sub");
//}

這樣, SubElement可以覆蓋getMessageToPrint()方法。

或者更好的是:

Element e = new SubElement();
e.print();

我會選擇不同的方法。

  1. 使用其他人建議的多態,擴展Element以添加print()方法(可以被子類覆蓋)或
  2. 定義輔助接口並使用策略和工廠模式的組合:

基類

 public class Element{}

派生類

 public class SubElement extends Element{}

輔助界面打印元素

public interface PrintHelper{
    void print(Element element);
}

工廠為給定元素獲得最佳PrintHelper

public class PrintHelperFactory{

    private final Map<Class<? extends Element>, PrintHelper> registeredHelpers =
        new HashMap<Class<? extends Element>, PrintHelper>();

    // Register a PrintHelper for a given Element class.
    public void registerHelper(final Class<? extends Element> clazz,
      final PrintHelper helper){
        this.registeredHelpers.put(clazz, helper);
    }

    // Get the most specific PrintHelper for a given Element.
    public PrintHelper getHelperForElement(final Element element){
        Class<? extends Element> clazz = element.getClass();
        while(!Object.class.equals(clazz)){
            if(this.registeredHelpers.containsKey(clazz)){
                return this.registeredHelpers.get(clazz);
            }
            clazz = (Class<? extends Element>) clazz.getSuperclass();
        }
        return null;
    }

}

客戶端測試類,作為Java Application運行

public class Main{

    public static void main(final String[] args){

        final PrintHelperFactory factory = new PrintHelperFactory();
        factory.registerHelper(Element.class, new PrintHelper(){
            @Override
            public void print(final Element element){
                System.out.println("Element");
            }
        });
        factory.registerHelper(SubElement.class, new PrintHelper(){
            @Override
            public void print(final Element element){
                System.out.println("Sub Element");
            }
        });

        // test it with an Element  
        final Element elem = new Element();
        factory.getHelperForElement(elem).print(elem);

        // test it with a sub class
        final Element sub = new SubElement();
        factory.getHelperForElement(sub).print(sub);

    }

}

產量

Element
Sub Element

暫無
暫無

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

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