2010-03-24 4 views
3

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

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

+1

«ключ» должен, вероятно, быть перечислением, а не char –

+0

@ David: Исправлено! – ArjunShankar

ответ

3

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

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

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

@implementation Factory 

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

Конечно, вы не должны создавать оба экземпляра сразу. Вы можете делать все, что вам нравится - кеш, ленивый груз, что угодно. Дело в том, что управление жизненным циклом Foo до Factory, отдельно от кода Foo. Тогда это становится намного легче. ¶ Все остальные объекты, которые нуждаются в Foo будут созданы и подключены через Factory и получите их Foo через сеттер:

@implementation Factory 

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

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

+0

Это правда, что его сложность, и, по словам очевидца, в его ответе, это только ухудшится. И после прочтения этого: [http://stackoverflow.com/questions/2410830/apple-singleton-example-query/2411685#2411685], я решил, что мне нужно сделать что-то более простое. Принуждение мультитона таким образом больше не кажется таким элегантным. – ArjunShankar

0

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

+0

Многоугольник - это шаблон дизайна, который расширяет концепцию одноэлементного: http://en.wikipedia.org/wiki/Multiton_pattern – ArjunShankar

+0

Вот пример того, почему нужно было бы два экземпляра (скорее, его _my_ причина для желания двух) : Я хочу получить доступ к базе данных sqlite3 из двух потоков. Теперь sqlite3 является потокобезопасным, если вы не разделяете соединения по потокам => Мне нужно убедиться, что каждый поток имеет свое собственное соединение.Если соединение sqlite3 соответствует экземпляру мультитона, и каждый поток может идентифицировать себя, тогда его хороший способ убедиться, что в потоке имеется ровно один экземпляр. – ArjunShankar

+2

Если это не просто упражнение по программированию, вы можете найти примеры того, как другие выполняли потоки sqlite - возможно, используя простые мьютексы вместо слишком сложных конструкций, таких как многотонные. –

2

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

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

+0

Вы правы. Я думал о том, чтобы обойти это, сделав init достаточно умным, чтобы не повторно инициализировать выделенные экземпляры (и добавить еще немного сложности в код). В принципе, теперь я чувствую, что вся идея принудительного мультитона плохо. – ArjunShankar

Смежные вопросы