Элегантная и "правильная" многотонная реализация в Objective C?

StackOverflow https://stackoverflow.com/questions/2507312

Вопрос

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

Это было полезно?

Решение

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

Если вам нравятся узоры, вы можете использовать что-то похожее на фабричный узор для изготовления ваших объектов.Фабрика позаботится о создании этих двух экземпляров и передаче их туда, где это необходимо.И Фабрика будет намного проще, чем Многотонная:

@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 будут созданы и подключены через фабрику и получат свои Foo через сеттер:

@implementation Factory

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

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

Другие советы

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

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

Вопрос по порядку ведения заседания:Откуда вы знаете, что у вас когда-либо будет только два экземпляра или вам нужно будет иметь два экземпляра?(Или хотите иметь два экземпляра?) Что, собственно, представляет собой точка о том, что у вас есть "Многотонник"?(И это вообще слово?)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top