2013-09-22 92 views
1

的情況區別實現接口的對象的實例,是,我有這個接口:通過枚舉值或通過其實現接口

interface ISymbol 
{ 

} 

和這些類:

class Letter implements ISymbol 
{ 

} 

class Number implements ISymbol 
{ 

} 

class LowerCaseLetter extends Letter 
{ 

} 

class UpperCaseLetter extends Letter 
{ 

} 

現在讓我們說我有這個功能,在不同的課堂上。 該類執行不會在ISymbol 類的實現所屬的邏輯:

class SymbolMonitor 
{ 
void func(ISymbol[] symbols) 
{ 
    for (ISymbol iSymbol : symbols) 
    { 
     // If the symbol is a number 
     // or a lower case letter do something. 
    } 
} 
} 

但我不想專門檢查這兩種類型,因爲我可能有ISymbol的其他執行類,將也需要相同的邏輯。

我的問題是關於首選的行動方式。 我有兩個解決問題的方法。 1.像這樣創建:

enum SymbolType 
{ 
    NORMAL, 
    SPECIAL1, 
    SPECIAL2, 
} 

,並添加到代碼:

interface ISymbol 
{ 
    SymbolType getType(); 
} 

class SymbolMonitor 
{ 
    void func(ISymbol[] symbols) 
{ 
    for (ISymbol iSymbol : symbols) 
    { 
      if(iSymbol.getType().equals(SymbolType.SPECIAL1)) 
        { 
         // Do special1 logic 
        } 
      if(iSymbol.getType().equals(SymbolType.SPECIAL2)) 
        { 
         // Do special2 logic 
        } 
    } 
} 
} 
  1. 我可以創建空的接口,並使用instanceof功能。

    interface ISpecialSymbol1 
    

    {

    }

    ISpecialSymbol2 {

    }

    類LowerCaseLetter延伸信接口實現ISpecialSymbol1 {

    }

    類Number實現ISymbol,ISpecialSymbol1 {

    }

,這樣函數將是:

class SymbolMonitor 
{ 
void func(ISymbol[] symbols) 
{ 
    for (ISymbol iSymbol : symbols) 
    { 
     if(iSymbol instanceof ISpecialSymbol1) 
     { 
      // Do special 1 logic. 
     } 
     if(iSymbol instanceof ISpecialSymbol2) 
     { 
      // Do special 2 logic. 
     } 
    } 
} 
} 

我認爲第二個選項是更簡單,但我是java的新手,我不確定什麼是正確的使用方法。

+3

使用多態對你有利。儘量避免'instanceof'並輸入檢查。 –

+0

你的意思是把邏輯推入課堂?因爲我有一個使用ISymbol的外部函數,而不是屬於類內部的邏輯。 – TomF

+2

有許多模式可以實現這種間接性。 「訪客」可能就是其中之一。一探究竟。 –

回答

2

接口聲明的方法:

interface ISymbol 
{ 
    public void doSomething(); 
} 

和任何執行類可以重寫並指定其所需的行爲。在這種情況下:

然後你可以直接調用ISymbol。DoSomething的()

void func(ISymbol[] symbols) 
{ 
    for (ISymbol iSymbol : symbols) 
    { 
     iSymbol.doSomething() 
    } 
} 
+0

doSomething函數必須處理ISymbol派生類不應該訪問的對象的實例,除非我想打破必須非常難看的邏輯層。 – TomF

+0

在這種情況下,'doSomething'方法可以重命名爲'canDoSomething()',它將返回一個布爾值。如果所有重寫方法都可以「doSomething」或false,則它們可以返回true。在for循環中,你可以有一個if條件if(iSymbol.doSomething())'然後doSomething() – SrikanthLingala

+0

那麼這正是我的意思是枚舉選項,只是使用枚舉而不是布爾vaues。 – TomF

1

你的問題是「Design Patterns: Elements of Reusable Object-Oriented Software」爲visitor pattern給出的動機的近逐字引用。在代碼中,這將是這樣的:

interface Visitor { 
    void visit(Letter letter); 
    void visit(Number number); 
    // ... 
} 

interface ISymbol { 
    void visit(Visitor v); 
} 

class Letter { 
    @Override void visit(Visitor v) { 
     v.visit(this); 
    } 
} 

class Number { 
    @Override void visit(Visitor v) { 
     v.visit(this); 
    } 
} 

使用枚舉是一個可行的選擇,如果遊客能保持不可知他們經營哪種類型的(因爲訪問者只使用方法,所有的記號)的。如果訪問者確實需要轉換爲相應的符號類型,我寧願訪問者模式。

我通常更喜歡一系列instanceof檢查訪問者模式,因爲訪問者模式使編譯器能夠驗證所有訪問者處理所有符號類型 - 所以如果添加符號類型,所有現有訪問者將不再編譯,直到您已經指定了如何處理這種新類型。

+0

我明白你的答案,我會接受它,但使用訪問者迫使我將大部分邏輯導出到上帝類中,以便所有邏輯將可用於代碼的所有層。 現在提出這個問題,我應該打破導致Coupling的圖層,以便訪問者可以訪問上層邏輯或使用枚舉。如果我使用的是枚舉,那麼爲什麼它更好呢? – TomF

+0

你對「上帝之類」有什麼含義?而且我不明白訪問者模式會如何破壞圖層(訪客實現不需要公開,也不會與訪客界面位於同一圖層中) – meriton

+0

我在一層之上有一個函數ISymbol繼承類的位置。 此函數對於ISymbol類型具有不同的功能。 要在這裏實現訪問者模式,我將不得不讓ISymbol訪問上述圖層的功能。 – TomF