2017-02-04 64 views
2

我的課程最初是從幾個單獨的addAListener()addBListener()removeAListener等開始的。這對一個類沒有那麼糟糕,但當類被另一個類內部使用並且擴展偵聽器被傳播出去時,它真的向外爆發。有沒有更好的方法來短路一個instanceof鏈?

一個簡單的解決方法是使用一個單一的界面,並整理出聽衆與instanceof

public interface Listener { 
} 

public class ListenerA extends Listener { 
} 

public class ListenerB extends Listener { 
} 

public class ListenerC extends Listener { 
} 

List<ListenerA> ofListenersA = new List<>(); 
List<ListenerB> ofListenersB = new List<>(); 
List<ListenerC> ofListenersC = new List<>(); 

void addListener(Listener listener) { 
    if (listener instanceof ListenerA) { 
     ofListenersA.add(listener); 

     return; 
    } 

    if (listener instanceof ListenerB) { 
     ofListenersB.add(listener); 

     return; 
    } 

    if (listener instanceof ListenerB) { 
     ofListenersB.add(listener); 

     return; 
    } 
} 

void removeListener(Listener listener) { 
    if (listener instanceof ListenerA) { 
     ofListenersA.remove(listener); 

     return; 
    } 

    if (listener instanceof ListenerB) { 
     ofListenersB.remove(listener); 

     return; 
    } 

    if (listener instanceof ListenerB) { 
     ofListenersB.remove(listener); 

     return; 
    } 
} 

但現在我有專門評估每個instanceof因爲你不能switch一類。

這不是試圖尋求優化,因爲我沒有多種偵聽器來檢查;而是一個關於在面向對象設計中這是否是不好的方法的問題。

更新

使用界面內枚舉短路的方法:

enum ListenerType { 
    ListenerTypeA, 
    ListenerTypeB, 
    ListenerTypeC 
} 

public interface Listener { 
    ListenerType getType(); 
} 

public class ListenerA extends Listener { 
    ListenerType getType() { 
     return ListenerType.ListenerTypeA; 
    } 
} 

public class ListenerB extends Listener { 
    ListenerType getType() { 
     return ListenerType.ListenerTypeB; 
    } 
} 

public class ListenerC extends Listener { 
    ListenerType getType() { 
     return ListenerType.ListenerTypeC; 
    } 
} 

List<ListenerA> ofListenersA = new List<>(); 
List<ListenerB> ofListenersB = new List<>(); 
List<ListenerC> ofListenersC = new List<>(); 

void addListener(Listener listener) { 
    switch (listener) { 
     case ListenerTypeA: { 
      ofListenersA.add(listener); 

      return; 
     } 
     case ListenerTypeB: { 
      ofListenersB.add(listener); 

      return; 
     } 
     case ListenerTypeC: { 
      ofListenersC.add(listener); 

      return; 
     } 
    } 
} 

void removeListener(Listener listener) { 
    switch (listener) { 
     case ListenerTypeA: { 
      ofListenersA.remove(listener); 

      return; 
     } 
     case ListenerTypeB: { 
      ofListenersB.remove(listener); 

      return; 
     } 
     case ListenerTypeC: { 
      ofListenersC.remove(listener); 

      return; 
     } 
    } 
} 
+0

如果你使用'instanceof',那麼你的設計可能是錯誤的。你爲什麼要分開跟蹤所有這些監聽器,並且如果你需要它們分開,爲什麼單個'addListener'方法? – chrylis

+0

因爲我有其他使用這個類的對象作爲私有成員的對象。所以當我想從上面提供監聽器時,我必須爲每個類再次實現每個添加/刪除監聽器。我將它們全部作爲單獨的監聽者的原因是因爲我爲每個事件分別循環了每個事件。 – Zhro

+0

我已經查看了許多開源項目,但我不記得任何使用單一方法的通用監聽器,你經常會想:爲每個監聽器創建一個方法並添加一些直觀的名稱。 – Enzokie

回答

0

有一個單一interface並定義enum。在interfaceabstract method中,您可以使用enum的實例作爲參數。

現在您只需要一個監聽器列表。

現在您可以根據操作或事件類型調用方法。在執行時,您可以按照enum instance type進行處理。

其他方式是有一個single interfacedifferent methods。按照發生的事件調用方法,並在實現時按照方法進行處理。

具有定義事件類型(類型爲enum,字符串或整數變量,但更喜歡enum)的變量的單個方法方法的優點是,如果在添加更多操作的情況下,您只需將它們添加到接口中而不是將需要很多改變。你只需要在枚舉中添加額外的動作(如果你有字符串或整數常量,那麼相應地你可以爲新動作定義額外的常量)。現在您可以使用新定義的操作類型調用相同的方法。

只需要注意避免Fat接口。您需要在太稀(每個方法的單個接口)和胖接口之間進行平衡。您可以將屬於邏輯相同任務的方法分組到接口中。太散亂的代碼也很糟糕,將每個(相關和不相關的)apis放在單個界面中也是不好的。

0

有(在我的經驗)總是一個更好的辦法,而不是使用instanceOf不知道你的代碼是很難說有什麼是最合適的,但根據以下情況是好的類型比較:

  • 地圖,它們的操作方式與基於類型的開關語句非常相似,只要您將地圖的關鍵點設置爲您希望打開的類型,然後就可以直接返回匹配時返回的地圖。

  • Command Pattern,其中您將偵聽器類層次結構替換爲abstract/concrete命令。然後你可以將實際行爲封裝到接收器中。

  • Visitor Pattern如果您想一次通知所有偵聽器,那麼訪問者模式可能適用,類型比較將通過您的偵聽器層次結構重新進行,作爲被訪問的元素。

我希望這有一些用途讓我知道,如果我離開基地。

1

我建議您添加一個類型來指定您感興趣的偵聽器類型。您還可以將該鍵更改爲其他類型,例如具有hashCode和equals的常規類。

enum ListenerType { 
    TYPE_A, TYPE_B, TYPE_C 
} 

interface Listener { 

} 

Map<ListenerType, Set<Listener>> listeners = new ConcurrentHashMap<>(); 

public void addListener(ListenerType type, Listener listener) { 
    listeners.computeIfAbsent(type, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())).add(listener); 
} 

public void removeListener(ListenerType type, Listener listener) { 
    listeners.computeIfPresent(type, (k, v) -> v.remove(listener) && v.isEmpty() ? null : v); 
} 

public Set<Listener> getListeners(ListenerType type) { 
    return listeners.getOrDefault(type, Collections.emptySet()); 
} 
0

我們在這種情況下使用了Visitor模式。 在添加Listener的新實現的情況下,用訪問者模式維護代碼也很容易。

相關問題