2

我对 Objective C 比较陌生,并且有一个关于围绕现有委托创建自定义委托的架构问题。它可能最好用伪代码来描述。抱歉,我无法确定如何使它更简洁。

总体期望架构总结

我在某个库中有一个调用 Web 服务的类,该类在 Web 服务异步返回时接受回调委托。这个低级库被包裹在一个门面(一个单例)中以保护客户不知道它,门面方法可以接受一个有效地包装低级库的委托的委托,因此客户可以在门面时将自己分配为委托(本身是一个委托)从 Web 服务调用中获取数据)。

换句话说,客户端实例 A 调用外观 [f makeCallWithDelegate:self],外观隐藏其内部工作,因此 A 只需实现外观的委托协议。

伪代码

低级类:

// 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");
}
...

回顾

Client 实例调用外观并将自己作为委托传递。外观依次调用低级类实例,将外观本身作为委托传递。门面听到来自低级类实例的响应,并将更好的结果返回给客户端实例。我正在解决的问题是如何确保在包装低级委托的响应时使用正确的外观委托。

用实例重申上述内容:客户端实例 A 调用外观 [f makeCallWithDelegate:self]。客户端实例 B 也调用外观 [f makeCallWithDelegate:self]。我需要确保客户端 A 用作客户端 A 调用的代表,客户端 B 用作客户端 B 调用的代表。

影响设计的注释

不能修改 LowLevelClass。如果可以的话,我可能会传递委托以调用“userdata”字段或其他东西......无论如何我都不喜欢这种方法,因为这会污染具有较高层知识的较低层类类。

外观是一个单例,有几个原因。也许这可以改变,我可以创建多个外观实例。

可能的解决方案

A. 现在,如果我可以保证 Facade 一次只被一个客户端使用,我可以将 the_delegate 存储在 Facade 成员变量中,我可以在 Facade success:selector; 中调用它。但是,我不能保证。几个不同的客户端实例可以调用门面,我需要确保每个客户端调用的委托都是客户端本身,而不是其他客户端(使用上面的实例示例,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 的新手)。

如果你做到了这一步,我感谢你(并祝贺你)。我想听听关于什么是解决这个问题的好设计的任何建议。

非常感谢你花时间陪伴。

4

1 回答 1

0

我相信@lnafziger 以上是正确的,B 是最好的答案(将外观更改为常规类,非单例,这也使设计远离单例问题)。在接受这个作为答案之前,我会等着看是否有任何其他建议出现。

于 2012-10-26T14:19:21.623 回答