2013-04-19 4 views
3

У нас есть одноэлементный класс в одной из наших статических библиотек. Это синглтон, потому что мы хотим быть в состоянии «помнить» его состояние во все времена. По сути, это синглтон управления пользователями.Как сделать мой Singleton класс расширяемым?

Имеет свойство User *user и имеет методы, такие как - (void)authenticateUser.

Мы хотим доставить это клиенту, который захочет создать свой собственный метод - (void)authenticateUser. Для этого я предположил, что они расширят класс UserManager и просто переопределяют этот метод.

Однако, поскольку это одноэлементный метод, он имеет следующие методы: - (id)sharedInstance и обычным способом alloc. Все они выглядят следующим образом:

static UserManager *_sharedInstance = nil; 

+ (id)sharedInstance { 
    @synchronized([UserManager class]) { 
     if(!_sharedInstance){ 
      id temp = [[self alloc] init]; 
      [temp class]; 
     } 
     return _sharedInstance; 
    } 
    return nil; 
} 

+ (id)alloc { 
    @synchronized([UserManager class]) { 
     NSAssert(_sharedInstance == nil, @"Attempted to allocate a second instance of a singleton"); 
     _sharedInstance = [super alloc]; 
     return _sharedInstance; 
    } 
    return nil; 
} 

Поэтому, учитывая это, можно создать подкласс и расширить этот UserManager класс? Могу ли я создать ChildUserManager, который переопределяет функцию? Или мне придется переписать эти методы singleton для работы с «новым» дочерним классом?

Есть ли способ изменить эти методы, чтобы третьи стороны могли легко расширить этот класс?

Благодаря

+0

Если статический не внутри Alloc, вы рискуете установить его кто-то. – Jano

+0

Предположительно, как статичность находится внутри реализации, она недоступна вне этого класса? –

+0

Правда, извините, это видно только в своем блоке компиляции. – Jano

ответ

0

Beter design будет использовать композицию, а затем наследование. Объявите протокол AuthenticationDelegate

@protocol AuthenticationDelegate 
@optional 
-(void) authenticateUser:(User*)inUser; 
@end 

Иметь недвижимость в UserManager, что по умолчанию указывает на UserManager.

@class UserManager : NSObject <AuthenticationDelegate> { 
    ...... 
} 

@property (assign) id<AuthenticationDelegate> authenticator 

+ (id)sharedInstance; 

Ваши клиенты, если они хотят, чтобы проверить подлинность их методом, то они должны подтвердить себя AuthenticationDelegate протокол и реализовать свои методы. Они должны установить свойство аутентификатора для своего класса, который ограничивается. Однако его синглтон. Поэтому они могут установить его, как только объект будет создан. Следовательно, они могут использовать свой Authenticator.

Но удостоверьтесь, что пункт подтверждения аутентификации указывает на нуль. Вы можете реализовать метод setAuthenticator: так, чтобы аутентификатор указывал на UserManager, когда клиенты устанавливают это на нуль.

static UserManager *_sharedInstance = nil; 

@implementation UserManager 

@synthasize authenticator; 

+ (id)sharedInstance { 
    @synchronized([UserManager class]) { 
     if(!_sharedInstance){ 
      id temp = [[self alloc] init]; 
      [temp class]; 
     } 
     return _sharedInstance; 
    } 
    return nil; 
} 

+ (id)alloc { 
    @synchronized([UserManager class]) { 
     NSAssert(_sharedInstance == nil, @"Attempted to allocate a second instance of a  singleton"); 
     _sharedInstance = [super alloc]; 
     return _sharedInstance; 
    } 
    return nil; 
} 

-(void)init { 
    self = [super init]; 
    if (self) { 
     self.authenticator = nil; 
    } 
} 

-(void)setAuthenticator:(id<AuthenticationDelegate>)inAuthenticator { 
    if (!inAuthenticator) { 
     __authenticator = self; 
    } else { 
     __authenticator = inAuthenticator; 
    } 
} 

#pragma mark - AuthenticationDelegate 

-(void) authenticateUser:(User*)inUser 
{ 
    // Your Authentication Code. 
} 

Надеется, что это помогает ...

+0

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

+0

Почему вы используете @synchronized, если среда iOS легко управляется - вы можете контролировать один доступ за раз? или вы предпочитаете обобщать? – seufagner

1

Лучше одноплодной картина:

// UserManager.h 

#import <Foundation/Foundation.h> 

@interface UserManager : NSObject 

+(instancetype)sharedInstance; 

// clue for improper use (produces compile time error) 
+(instancetype) alloc __attribute__((unavailable("alloc not available, call sharedInstance instead"))); 
-(instancetype) init __attribute__((unavailable("init not available, call sharedInstance instead"))); 
+(instancetype) new __attribute__((unavailable("new not available, call sharedInstance instead"))); 

@end 


// UserManager.m 

#import "UserManager.h" 

@implementation UserManager 

+(instancetype) sharedInstance { 
    static dispatch_once_t pred; 
    static id shared = nil; 
    dispatch_once(&pred, ^{ 
     shared = [[super alloc] initUniqueInstance]; 
    }); 
    return shared; 
} 

-(instancetype) initUniqueInstance { 
    return [super init]; 
} 

@end 

Если подкласс, единственный экземпляр будет установлен на все, что называется первым, например:

[Animal sharedInstance]; // instance set to Animal 
[[Cow sharedInstance] moo]; // unknown selector 'moo' because the instance is Animal 

Это само по себе будет работать tho:

[[Cow sharedInstance]moo]; 
+0

Вы говорите, что то, что я прошу в моем вопросе, невозможно с помощью синглета? Поэтому я должен превратить его в стандартный объект? Или вы просто даете мне совет по использованию синглетов? –

+0

В Objective-C вы не можете запретить клиенту создавать n экземпляров синглтона с использованием функций времени исполнения. Существует более совершенная идиома для синглетов, использующих dispatch_once. Вы должны признать, что расширение синглтона немного странно. Будучи Objective-C настолько динамичным, что нет абстрактных классов, и даже если вы можете отключить метод init, IMO лучше, если вы документируете класс и позволяете здравому смыслу клиента делать все остальное. – Jano

+0

hmm ... ok. Определенно пища для размышлений. Я мог бы заглянуть в нее и посмотреть, как много работы будет, чтобы отменить все это! :) thanks –

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