2013-04-01 148 views
1

我有一些類Base的實現,並且所有對象都收集在List<Base>中。如何根據對象instanceof選擇要執行的操作?

如何根據instanceof這些對象調用特定的action而不必使用詳細的instanceof檢查?我怎樣才能根據這些對象的實例選擇一個service方法來執行,而不必關心執行哪個對象。應該以某種方式自動選擇正確的服務方法,而不用指定類型或實例檢查。

class Base; 
class Foo extends Base; 
class Bar extends Base; 

class Service { 
    List<Base> bases; 

    public void someMethod() { 
     for (Base base : bases) { 
      //perform some instanceof dependend action. 
      //these actions cannot be inside of any Base class as it makes use of other objects too. 
      if (base instanceof Foo) { 
       fooService.action((Foo) base); 
      } 
      if (base instanceof Bar) { 
       barService.action((Bar) base); 
      } 
     } 
    } 
} 


//custom service methods 
class FooService { 
    void action(Foo foo) { 
    } 
} 

class BarService { 
    void action(Bar bar) { 
    } 
} 
+2

這種反模式的氣味。戰略模式可以在更少的情況下使用更脆弱的實例嗎? –

+1

或者使用某種工廠來加載服務方法。 – Marvo

+0

那麼,對於一個「策略」,我首先必須知道我正在處理的是哪個「Base」實例,對吧?因爲我最終會遇到'FooStrategy'和'BarStrategy',如果我想在所有'Foo'實例上調用'FooStrategy',我必須首先執行'instanceof'檢查... – membersound

回答

4

多態性是一種可能性。如果Base類包含抽象action()方法,則可以直接調用它,而不使用if語句。

另一個是註冊表。對於Base的每個子類,您都可以將映射註冊到服務類。在someMethod()中,查找註冊表中的類,獲取相應的服務類,然後調用它。

順便說一下,冗長並不是instanceof語句的唯一問題。一旦創建了Base的新子類,您用這些代碼編寫的代碼就會中斷。滿足Open/Closed principle可能會導致代碼不易損壞。

+0

是的,但是如上所述,我不能在我的Base類中使用'action()',因爲它更像是一個服務方法,它也可以使用其他對象。否則在多態性方面很容易,但我正在尋找一種方法來處理這個問題,而不必將邏輯放在'Base'實現中。 – membersound

+0

你有沒有考慮過第二種可能性 - 一個註冊表? –

+0

是的,這可能是我唯一可以去的方式,儘管我對註冊表查找並不感到滿意。從設計的角度來看,它也感覺不對。那麼改變'Base'對象並引入'getService()'方法可能會更好,這樣每個實現都會被迫提供它自己的服務。 – membersound

2

一種可能的解決方案是使用Visitor模式。您需要將FooServiceBarService合併成一個類,並且這兩種方法都有超載的action()方法。然後,您需要將accept()方法添加到FooBar類別中的每一個類別,然後可以調用相應的action()方法。欲瞭解更多詳情,請參閱http://en.wikipedia.org/wiki/Visitor_pattern

有可能是其他更合適的design patterns可以解決這個問題。我建議你研究一下。

+0

確定那很好,但是:如果我喜歡這些特定於實例的方法中的5個,該怎麼辦?這意味着我必須寫5個訪問者,併爲每個新的實例依賴行爲創建一個新的訪問者。 – membersound

+0

@member由「特定於實例」的方法,你的意思是每個Service類中有5個方法嗎?如果是這樣,那麼你幾乎肯定會需要使用不同的設計模式。我確信通過一些研究,你可以找到適合你需求的東西。 –

+0

是的,比方說我有一些'add(),delete(),modify(),update()'方法。它們中的每一個都應該依賴於實例,這意味着'Foo'的add()'應該與'Bar'的'add()'不同。無論如何,我想保留所有'基本'對象在'List '中,並且通過迭代在列表中執行'add(base)'...您是否有更好設計的建議。因爲我在這裏問的是,我自己到目前爲止還沒有找到一個更好的... – membersound

0

我曾經得到解決這個問題最接近的是:

class Base{}; 
class Foo extends Base{}; 
class Boo extends Base{}; 

附加BaseService接口,因此每個服務類中使用同樣的方法:

public interface BaseService<T extends Base> { 

void action(T base); 

} 

BooService:

public class BooService implements BaseService<Boo> { 

public void action(Boo boo){ 
    System.out.println("Action performed by BooService"); 
    } 
} 

FooService:

public class FooService implements BaseService<Foo> { 

public void action(Foo foo){ 
    System.out.println("Action performed by FooService"); 
    } 
} 

附加ServiceSupplier類,將通過對象調用適當的服務基地:

public class ServiceSupplier { 

private Map<Class<? extends Base>, BaseService> services; 

public ServiceSupplier(){ 
    initializeServiceMap(); 
} 

public BaseService getServiceOfType(Class<? extends Base> clazz){ 
    return services.get(clazz); 
} 

private void initializeServiceMap() { 
    services = new HashMap<>(); 
    services.put(Foo.class, new FooService()); 
    services.put(Boo.class, new BooService()); 
    } 
} 

和您的服務類:

public class Service { 
List<Base> bases; 
ServiceSupplier serviceSupplier; 

public Service(){ 
    serviceSupplier = new ServiceSupplier(); 

    bases = new ArrayList<>(Arrays.asList(new Foo(), new Boo())); 
} 

public void someMethod() { 
    bases.forEach(base -> serviceSupplier.getServiceOfType(base.getClass()).action(base)); 
    } 
} 

可能看起來就像剛剛去除幾個「如果」聲明,但有更多的服務,你需要做的就是將它們添加到initializeServiceMap()方法。

相關問題