3

你会称这个在objective-c中的multiton的实现是“优雅的”吗?我以编程方式“不允许”使用allocandallocWithZone:因为需要根据密钥来决定分配或不分配内存。

我确定我只需要使用两个实例,所以我使用“switch-case”而不是地图。

#import "Multiton.h"

static Multiton *firstInstance = nil;
static Multiton *secondInstance = nil;

@implementation Multiton

+ (Multiton *) sharedInstanceForDirection:(enum KeyName)direction {

    return [[self allocWithKey:direction] init];
}

+ (id) allocWithKey:(enum KeyName)key {

    return [self allocWithZone:nil andKey:key];
}

+ (id) allocWithZone:(NSZone *)zone andKey:(enum KeyName)key {

    Multiton **sharedInstance;

    @synchronized(self) {

        switch (key) {
            case KEY_1:
                sharedInstance = &firstInstance;
                break;
            case KEY_2:
                sharedInstance = &secondInstance;
                break;
            default:
                [NSException raise:NSInvalidArgumentException format:@"Invalid key"];
                break;
        }
        if (*sharedInstance == nil)
            *sharedInstance = [super allocWithZone:zone];
    }

    return *sharedInstance;
}

+ (id) allocWithZone:(NSZone *)zone {

    //Do not allow use of alloc and allocWithZone
    [NSException raise:NSObjectInaccessibleException format:@"Use allocWithZone:andKey: or allocWithKey:"];
    return nil;
}

- (id) copyWithZone:(NSZone *)zone {

    return self;
}

- (id) retain {

    return self;
}

- (unsigned) retainCount {

    return NSUIntegerMax;
}

- (void) release {

    return;
}

- (id) autorelease {

    return self;
}

- (id) init {
    [super init];
    return self;
}

@end

PS:我还没有尝试过这是否有效,但它的编译很干净:)

4

3 回答 3

3

我发现单身是个坏主意,这看起来是可怕的四倍。代码相当复杂,你肯定会花几个小时来寻找其中的细微错误,但你可能永远不会对此感到舒服。那不好。你应该扔掉这个可憎的东西,并以不需要太多思考的其他方式将你的对象连接在一起。

如果你喜欢模式,你可以使用类似于工厂模式的东西来连接你的对象。工厂将负责创建这两​​个实例并将它们传递到需要的地方。工厂将比 Multiton 简单得多:

@interface Factory : NSObject {
    Foo *foo1, *foo2;
}
@end

@implementation Factory

- (id) init {
    [super init];
    foo1 = [[Foo alloc] init];
    foo2 = [[Foo alloc] init];
    return self;
}

当然,您不必一次创建两个实例。你可以在那里做任何你喜欢的事情——缓存、延迟加载等等。关键是将生命周期管理留给工厂,与代码Foo分开。Foo然后它变得容易得多。¶ 所有其他需要的对象Foo都将通过 Factory 创建和连接,并将Foo通过 setter 接收它们:

@implementation Factory

- (id) wireSomeClass {
    id instance = [[SomeClass alloc] init];
    [instance setFoo:foo1];
    [instance setAnotherDependency:bar];
    return [instance autorelease];
}

这比您问题中的代码要简单得多。

于 2010-03-24T17:26:12.693 回答
2

不要覆盖分配。重写 alloc 以返回以前分配的类实例的问题是,当 +sharedInstance 调用 [[Multiton alloc] init]... +alloc 将返回旧实例,然后-init 将重新初始化它!最佳实践是覆盖 -init,在返回缓存实例之前执行缓存查找并调用 [self release]。

如果您真的担心额外的 +alloc 的成本(它并不多),您还可以在 +sharedInstance 中进行缓存查找,然后确保您的所有客户端都通过 +sharedInstance 访问实例以避免额外的分配。

于 2010-03-24T13:50:04.650 回答
0

程序问题:你怎么知道你只会有两个实例,或者需要两个实例?(或者想要两个实例?)确切地说,拥有“Multiton”的意义何在?(这甚至是一个词吗?)

于 2010-03-24T12:00:33.873 回答