在Objective-C中所谓的“类集群”到底是什么?


91

我在读NSArray就是这样。听起来很沉重。我的办公桌上有7本关于Objective-C,Cocoa和C的真书。它们都没有提到类集群,至少在书的后面的索引中找不到。那是什么


糟糕,下次我会考虑为该词添加链接。如果您对以前的问题的答案有评论,我会在那儿回答。
Georg Fritzsche)

2
FWIW:最近(2013年12月),Apple建议使用类群集作为在使用iOS 7时处理与iOS 6的向后兼容性的方法。这是在Apple Tech Talks 2013 /柏林的“架构现代应用程序,第2部分”会议上。苹果公司表示,他们将在上次活动(12月17日)之后不久发布会议视频。因此,这可能有助于了解iOS 6/7更改的实际上下文中的类集群。
brainray 2013年

Answers:


42

从苹果公司的文档......。简而言之,这是Foundation框架中使用的设计模式,这可能就是为什么ObjC书籍中未提及它的原因。

类集群是一种将公共的抽象超类下的多个私有的具体子类分组的体系结构。以这种方式对类进行分组为用户提供了简化的界面,该用户仅看到公开可见的体系结构。


1
罗夫毛。谢谢。下次去谷歌。以为如果不在我的胖书里,那只能在你的头上;)
openfrog

1
缺少此链接的一件事是有关如何最好地更改ARC实现的说明。
Hyperbole 2012年

193

我不知道Steve所引用的CDP中有什么内容,但基本上,Objective-C类集群是一种支持实现抽象Factory模式的构造。

这个想法很简单:您想要提供一个Factory(集群)接口,该接口以最少的描述制造并返回一个Factory对象的特定具体实例,该实例满足Factory(集群)接口描述的集群家族的行为。

一个简单的具体示例:该示例提供一个Laugh工厂,该工厂产生特定笑声类型(例如Guffaw,Giggle)的具体类。注意Laugh initWithLaughter:方法。

在Laugh.h中:

#define kLaughWithGuffaw  1
#define kLaughWithGiggle  2

@interface Laugh: NSObject {}
- (Laugh *) initWithLaughter:(NSUInteger) laughterType;
- (void) laugh;
@end

在Laugh.m中:

@interface Guffaws:Laugh {}
- (void) laugh;
@end

@interface Giggles:Laugh {}
- (void) laugh;
@end

@implementation Laugh
- (Laugh *) initWithLaughter:(NSUInteger) laugherType {
    id instanceReturn=nil;
    ; // Removed for ARC [self release]
    if ( laughterType == kLaughWithGuffaw )
        instanceReturn = [[Guffaws alloc]init];
    else if( laughterType == kLaughWithGiggle )
        instanceReturn = [[Giggles alloc]init];
    else
        ; // deal with this
    return instanceReturn;
}

- (void) laugh {
    NSLog(@"Humbug");
}
@end

@implementation Guffaws
    - (void) laugh {
        NSLog(@"OH HA HA HOWAH HA HA HA");
    }
@end

@implementation Giggles
    - (void) laugh {
        NSLog(@"Tee hee");
    }
@end

24
虽然提供文档和书籍链接的其他答案很好,但我喜欢它,因为它使您轻松而轻松地了解如何实际执行此操作。谢谢
jamone 11-4-26

这个例子很好,但是在典型的Factory模式中,子类是公共的。在类集群中,子类是私有的。developer.apple.com/library/ios/documentation/general/…–
maxpower

1
@AdriàNavarro,因为它们在中声明,所以对外部不可见.m-file
hfossli 2014年

4
(1)init方法中释放self 并返回其他东西有多安全?有苹果公司提供的代码示例吗?(2)另外,您大概正在使用代码创建实例,例如[[Laugh alloc] initWithLaughter:kLaughWithGiggle]。注意如何Laugh分配不必要的,因为它将在此调用后立即释放。当您可以创建这样的类方法时,为什么要这样做呢?它可以[Laugh laughWithLaughter:kLaughWithGiggle]为您提供私有子类的所有优点,同时又避免了上面的问题1和2?
有意义的2014年

1
@Senseful你是对的。在现实生活中,+alloc返回实现各种-initWith:方法的单例工厂类。-initWith:然后,如果需要,则工厂类的方法负责根据给定的方法参数分配和初始化具体的子类,或者在某些情况下可能根本不分配任何内容(例如-[NSString initWithString:])。您可以通过返回值检查试试吧+[NSString alloc]+[NSArray alloc]
达伦-

25

从词汇表中群集的Stephen Kochan在目标c中的编程第498页开始:

将一组私有的具体子类分组的抽象类,通过抽象类为用户提供简化的接口。


5
+1用于引用Objective-C书中的答案,特别是针对原始问题。那也是一本好书。
奎因·泰勒

(+1)为极佳的清晰度。我将其称为“工厂”模式的问题在于,这样的名称仅关注对象的创建,而不关注抽象超类管理的私有子类的幕后交互。的确,甚至称此超类为“抽象”也可能会产生误导,因为它实际上(内部)完全依赖于其自身的子类,因此不是通常对其子类一无所知的普通抽象类。
devios1

18

类群集为一组具体的私有子类实现提供单个公共接口。一个Objective-C程序员经常使用类集群,而很少意识到它-这就是类集群的全部要点。类集群的工作是将实现细节的复杂性隐藏在公共接口的后面。

许多Foundation类都是类簇,例如NSString,NSArray,NSDictionary和NSNumber。当您调用[NSString stringWithFormat:]类集群时,将为您提供一些实现该NSString接口的具体类。它可以是一个NSConcreteStringNSCFStringNSFooBarString,等哪一个类簇为您提供了基于构造函数或初始化程序您调用和参数。

因此,类集群是Objective-C编程中最强大的概念之一。

  • 非常容易实现
  • 易于更改基础实现,而无需更改调用它的代码。
  • 易于在运行时提供不同的具体实现(即测试资源或模拟对象)
  • 由于上述原因,易于测试和重构

如果您来自其他语言,则可能熟悉“四人帮”模式。类群集具有抽象工厂和外观模式的元素。

Apple的公共文档非常广泛地介绍了类集群(以及如何实现和扩展它们)。不幸的是,我发现对于许多iOS开发人员而言,此模式和其他可可特定模式都是盲点。

可可核心能力:班级集群

可可基础指南:类群

GitHub上提供了如何实现自己的类集群的示例


7

NSArray类集群不是“重量级”的,它是一种使用数组类的任意数量的实现的方式,而您的代码无需了解或关心特定的实现。在后台,有一些适用于不同用例的NSArray具体子类,例如大型稀疏数组或包含在编译时已知的特定数量元素的数组。

NSArray,NSString和NSNumber是您最常遇到的类集群。


6
具有讽刺意味的是,实际上,每个群集不再使用一个具体的类-NSCF {Array | String | Number}-实现更改是该类内部的。无论如何,据我所知。甚至NSArray和NSMutableArray实例也显示相同的类。
Chuck 2010年

1
@Chuck-情况如何?如果NSMutableArray和NSArray报告自己是同一类,[myArray isKindOfClass:[NSMutableArray class]]即使它不应该返回YES?
罗伯特

1
@罗伯特:的确在我发表评论时就是这种情况。如今,Apple已用__NSArrayM和__NSArrayI替换了NSCFArray,所以我认为不再如此,但是我仍然不愿意依靠它,因为他们总是可以再次更改它。
Chuck
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.