# 28、通过协议提供匿名对象

若接口背后有多个不同的实现类，而你有不想指明具体使用哪个类，那么可以考虑使用`遵从某协议的纯id类型`--->*因为有时候这些类可能会边，有时候它们又无法容纳于标准的类继承体系中，因而不能以某个公共基类来统一表示*。

​ 如：代理（类型不重要，只要遵循协议就行）

```objectivec
@property (nonatomic, weak) id <XXXDelegate> delegate;
```

​ 如：NSDictionary设置键值对方法

```objectivec
- (void)setObject:(id)object forKey:(id<NSCopying>)key;
```

​ 如：处理数据库连接的程序库，以匿名对象来表示从另一个库中返回的对象

```objectivec
@protocol XXXDatabaseConnection
- (void)connect;
- (void)disconnect;
- (void)isConnect;
- (NSArray *)performQuery:(NSString *)query;
@end
@interface XXDataBaseManager: NSObject
+ (id)sharedInstance;
// 返回连接对象
- (id<XXXDatabaseConnection>)connectionWithIdentifier:(NSString)identifier; 
@end
```

​ 如此，处理数据库连接所用的类名就不会泄露，可能来自不同款家的类型现在均可用同一个方法返回了。

​ 再如：`CoreData`框架在负责查询接口的`NSFetchedResultsContoller`中，有个sections属性表示数据分区，是个数组如下：

```objectivec
NSArray *sections = controller.sections;
id <NSFecthedResultsSectionInfo> sectionInfo = section[section];
NSUInteger numberOfObjects = sectionInfo.numberOfObjects;
```

​ *在幕后，此对象可能使由处理结果的控制器所创建的内部对象，没必要把表示翅中数据的类对外公布，因为使用控制器的人绝对不关心查询结果中的数据分区使如何保存的，他们只要知道可以在这些对象上查询数据就行*

要点：

* 协议可在某种程度上提供匿名类型。具体的对象类型可以淡化成`遵从某协议的id类型`，协议里规定了对象所应实现的方法（如果具体类型不重要，重要的使对象能够响应（定义在协议里的）特定方法，那么可使用匿名对象来表示）
* 使用匿名对象来隐藏类型名称（或类名）
