Элегантная и «правильная» многотонная реализация в Objective C? - PullRequest
3 голосов
/ 24 марта 2010

Вы бы назвали эту реализацию мультитона в target-c «элегантной»? Я программно «запретил» использование alloc и allocWithZone:, потому что решение о выделении или не выделении памяти должно приниматься на основе ключа.

Я точно знаю, что мне нужно работать только с двумя экземплярами, поэтому я использую '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: я еще не пробовал, работает ли он еще, но он компилируется чисто:)

Ответы [ 3 ]

3 голосов
/ 24 марта 2010

Я считаю синглеты плохой идеей, и это выглядит примерно в четыре раза ужаснее. Код довольно сложный, вы можете быть уверены, что потратите немало часов на то, чтобы отследить тонкие ошибки в нем, и вы, вероятно, никогда не будете чувствовать себя комфортно. Это не хорошо. Вы должны выбросить эту мерзость и соединить свои объекты другим способом, который не требует большого количества размышлений.

Если вам нравятся шаблоны, вы можете использовать что-то похожее на шаблон Factory, чтобы связать ваши объекты. Фабрика позаботится о создании этих двух экземпляров и передаче их по мере необходимости. И Фабрика будет намного проще, чем 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 через установщик:

@implementation Factory

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

Это гораздо проще, чем код из вашего вопроса.

2 голосов
/ 24 марта 2010

Не переопределять alloc. Проблема с переопределением alloc для возврата ранее выделенного экземпляра класса, как вы делаете, заключается в том, что когда + sharedInstance вызывает [[Multiton alloc] init] ... + alloc вернет старый экземпляр, тогда -init будет переинициализируйте его! Рекомендуется переопределить -init, выполнить поиск в кэше и вызвать [self release] перед возвратом кэшированного экземпляра.

Если вы действительно обеспокоены стоимостью этого дополнительного + alloc (это не так много), вы также выполняете поиск в кэше в + sharedInstance, а затем гарантируете, что все ваши клиенты получают доступ к экземпляру через + sharedInstance, чтобы избежать дополнительного выделения.

0 голосов
/ 24 марта 2010

Точка порядка: откуда вы знаете, что у вас будет только два экземпляра или вам нужно два экземпляра?(Или хотите иметь два экземпляра?) Что именно означает точка наличия «Мультитона»?(И это даже слово?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...