2010-08-19 18 views
4

假設我目前正在設計一個需要使用全球定時系統的應用程序(這是一個橫切關注點)。我需要從應用程序中的任何地方訪問全球計時系統中的數據,而不是我可以看到「應用程序的這部分需要它,而另一部分則不需要」。如何處理面向對象應用程序中的交叉問題?使用Singleton?依賴注入?什麼?

我的問題是,我應該設計作爲一種環境上下文(在這種情況下,單身人士),還是我應該嘗試設計其他方式來適應這個?

我當然不覺得讓我的所有類都必須通過構造函數注入才能讓這個全局時序類傳遞給它們。很多時候我不得不將這個參考傳遞給下一個鏈,直到某個類最終需要它爲止。另一方面,從閱讀的角度來看,這會使事情變得更加清晰(它明確了我的班級的依賴關係)。

人們通常會如何處理這個問題?有沒有其他技術可以幫助解決這個問題? AOP也許?

PS:全球計時系統只是我從我正在閱讀的書中拿出的一個想法。日誌系統將是這類問題的另一個很好的例子。

感謝

回答

2

正如你所建議的,Aspect Oriented Programming (AOP)的設計只是考慮到這種事情,所以我肯定會檢查出來。

儘管構造函數注入在這種情況下似乎很麻煩,但使用IOC container可能有助於減輕您的痛苦。單身人士似乎很適合這項法案,但由於靜態問題,他們帶來了可測試性方面的問題 - 但您可以將其分解爲兩部分。

+0

關於將它分成2的情況如何? – 2010-08-19 17:04:53

+1

@devoured - 這是我在Roy Osherove的「單元測試藝術」中讀到的,關於讓單體的工廠部分與靜態部分分離,因此您可以在測試中替換它以返回您喜歡的內容。這有一點關於它:http://weblogs.asp.net/rosherove/archive/2007/06/10/tips-for-testable-code-and-for-testing-legacy-code.aspx – 2010-08-19 17:10:30

0

如果每個人都需要它,它是一種的一個(就像你提到的日誌),它絕對是一個單例。

0

我認爲你是對的,有些類型不適合構造函數注入;有時你需要以一種更廣泛的方式跟蹤某種類型的上下文,而不是在一組對象中。

當我面對這個問題時,我會經常創建一個Singleton,但是初始化邏輯調用依賴注入框架來做實際的實例化。這導致了在特定的靜態方法上的耦合(有些人會反對這一點) - 但同時我可以自由地改變實現,只要我喜歡它(也許某些類型在測試項目中有不同的實現,或者其他的東西)。而且我得到的好處是不必在所有對象構造函數之間傳遞一個非常常見的類型。

當然,你只應該這樣做,當時很多地方需要的類型真的是。否則,使用普通的構造函數注入。確切地說,「沒關係」由您來決定。

+0

「但有初始化邏輯調用依賴注入框架來做實際的實例」,這確實是一個好主意。 – 2010-08-19 17:06:23

0

靜態單例類是大多數時候我看到這個問題的方式。使用記錄作爲一個更常見的橫切關注點,我總是看我的日誌調用看起來像這樣:

public class SomeClassThatDoesStuff 
{ 
    private static readonly ILog log = 
      LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

    public void DoStuff() 
    { 
     log.Info("Doing something"); 
    } 
} 

你是全球時間類似乎是一個類似類型的橫切關注點,我會的以同樣的方式處理它

我同意用DI做這件事將是乏味而不實際的。

1

我做什麼用AOP:

 

public abstract aspect AutoInjectAspect<T> { 

    /** 
    * Implemented by the concrete class to decide what value to return. 
    * @param joinPoint 
    * @return 
    */ 
    abstract public T getInjectedValue(JoinPoint joinPoint); 

    protected pointcut autoInjectField() : get(@AutoInject T *); 

    /** 
    * override the "get" of the otherwise null value with the 
    * value to be injected 
    * @return the injected field 
    */ 
    T around(): autoInjectField() { 
     return getInjectedValue(thisJoinPoint); 
    } 
} 
 

後做了一個具體方面:

 

public aspect SLF4jLoggerInjector extends AutoInjectAspect<Logger> { 
    @Override 
    public Logger getInjectedValue(JoinPoint joinPoint) { 
     Class classInjected = joinPoint.getStaticPart() 
       .getSignature().getDeclaringType(); 
     Logger logger = LoggerFactory.getLogger(classInjected); 
     return logger; 
    } 
} 
 

然後做一個註解「@AutoInject」,並把那個在球場上要注入。

這就是說,你也可以是國際奧委會的集裝箱航線。

1

無論你是否將它作爲單例實現,我仍然建議你通過依賴注入傳遞它。我也建議你不要自己實現一些東西,並且遵循一個DI框架,給你一個單一的上下文,任何一級IOC庫都可以做。