我對Objective C比較新,並且有關於在現有代表周圍創建自定義代表的體系結構問題。這可能是最好的僞代碼描述。對於長度的道歉,我無法確定如何使它更簡潔。如何最好地設計包裝其他代表的自定義代表
總體所需的架構總結
我有一些圖書館,使一個Web服務,這需要回調的委託時,Web服務返回異步調用的類。這個底層庫被包裝在一個門面(一個單例)中,以防止客戶知道它,而門面方法可以採用委託來有效地包裝底層庫的委託,因此客戶可以在門面(本身就是一個委託)從Web服務調用中獲取數據)。
換句話說,客戶端實例A調用facade [f makeCallWithDelegate:self],並且Facade隱藏其內部工作,所以只需實現Facade的委託協議。
僞
低電平類:
// The low-level class that calls a web service
// LowLevelClass.h
@protocol LowLevelClassDelegate
- (void)success:(LowLevelClass*) c;
@end
@interface LowLevelClass
- (void)makeAsynchronousCallWithDelegate:(id <LowLevelClassDelegate>) d;
@end
// LowLevelClass.m omitted
門面包裹低電平類。此問題已注意到在makeCallWithDelegate選擇,並在成功委託回調:
// partial Facade.h
@protocol FacadeDelegate
- (void)success;
@end
@interface Facade <LowLevelClassDelegate> // the facade handles the delegate calls of the LowLevelClass
...
- (void)makeCallWithDelegate:(id <FacadeDelegate>) d;
...
@end
// Facade.m (pseudocode)
@implementation Facade
- (void)makeCallWithDelegate:(id <FacadeDelegate>) the_delegate {
LowLevelClass * llc = ... // get instance
[llc makeAsynchronousCallWithDelegate:self]; // delegate to self, catch events
// Issue: have to somehow pass the_delegate to the "success" method below,
// or have it available
}
// LowLevelClassDelegate implementation, hands result to the FacadeDelegate
- (void)success:(LowLevelClass*) c {
// Issue: need the_delegate to get down here somehow, or be reachable.
[the_delegate success]
}
@end
客戶端:
// Client.m fragment, client implements the FacadeDelegate protocol
...
- (void)makeFacadeGetData {
[facade makeCallWithDelegate:self];
}
- (void)success {
NSLog(@"Hooray");
}
...
重溫
客戶實例調用的門面和本身作爲傳遞代表。外觀依次調用低級別類實例,將外觀本身作爲委託傳遞。 Facade會聽到來自低級別實例的響應,並向Client實例返回更好的結果。我正在解決的問題是如何確保在包裝低層委託的響應時正確使用正面的委託。
重申上面的例子:客戶端實例A調用門面[f makeCallWithDelegate:self]。客戶端實例B還調用門面[f makeCallWithDelegate:self]。我需要確保客戶端A被用作客戶端A的呼叫的委託,並且客戶端B被用作客戶端B的呼叫的委託。
注影響設計
的LowLevelClass不能被修改。如果可以的話,我可能會通過委託來稱爲「用戶數據」字段,或者其他什麼......我不是那種方法的粉絲,因爲這會污染具有較高層知識的較低層類類。
立面是一個單身人士,原因有幾個。也許這可以改變,我可以創建多個門面實例。
可能的解決方案
A.現在,如果我可以保證一次一個客戶端使用外觀,我可以將the_delegate存儲在Facade成員變量中,並且可以在Facade成功中調用它:selector;不過,我不能保證。幾個不同的客戶端實例可以調用Facade,我需要確保每個客戶端的調用委託都是客戶端本身,而不是其他客戶端(使用上面的實例示例,A需要處理A的調用,而B需要處理B的)。
B.我可以讓外觀成爲一個非單例類,並將the_delegate存儲在成員變量中。也許這是最好的解決方案......儘管如此,仍然有些問題。
C.我在想,也許我可以爲每個調用makeCallWithDelegate分配一個唯一的鍵,而門面單例實例將存儲一個調用鍵和爲該調用傳入的委託的字典。 (注意:唯一對我有意義的關鍵是LowLevelClass指針的實際值 - 畢竟,如果我生成一個隨機字符串ID,我只是推遲了這個問題 - 但這種感覺有點不穩定)。 「成功」的方法將有機會獲得的字典,所以會調用正確的委託:
// Facade.m (pseudocode)
@implementation Facade
- (void)makeCallWithDelegate:(id <FacadeDelegate>) the_delegate
{
LowLevelClass * llc = ... // get instance
NSString* uniqueKey = makeUniqueKeyFromPointerValue(llc);
[self.delegateDictionary setObject:the_delegate forKey:uniqueKey];
[llc makeAsynchronousCallWithDelegate:self]; // delegate to self, catch events
}
// LowLevelClassDelegate implementation, hands result to the FacadeDelegate
- (void)success:(LowLevelClass*) c
{
NSString* uniqueKey = makeUniqueKeyFromPointerValue(c);
id<FacadeDelegate> del = [self.delegateDictionary objectForKey:uniqueKey];
[del success]
}
@end
我希望上述足夠詳細和清楚。畢竟,我感到困惑自己(再次,目標C新)。
如果你已經做到了這一點,我感謝你(並祝賀你)。我想聽聽任何關於這個問題的好設計的建議。
非常感謝您的時間。
好問題,但你已經告訴我們答案。它是B. :)因爲你需要爲這個特定的調用存儲委託,所以通常的做法是每次都需要創建一個單獨的實例。 – lnafziger
@lnafziger - 很好笑,因爲我正在用emacs起草這個問題,並且直到我發帖爲止,我都沒有將門面轉換爲非單身人士。我一直對單身人士持懷疑態度。文章https://sites.google.com/site/steveyegge2/singleton-considered-stupid有這樣的說法:「我會說,如果您仍然覺得需要使用Singleton對象,請考慮使用Factory Method相反的模式......使用真實物體爲您提供額外的靈活性,您會很高興。「 –