简体   繁体   English

如何使我的单例类可扩展?

[英]How to make my singleton class extendable?

We have a singleton class in one of our static libraries. 我们在一个静态库中有一个单例类。 It is a singleton because we want to be able to "remember" its state at all times. 这是一个单身人士,因为我们希望能够随时“记住”其状态。 In essence it is a User management singleton. 从本质上讲,它是一个用户管理单例。

It has a property User *user and it has methods such as - (void)authenticateUser . 它有一个User *user属性,它有- (void)authenticateUser

We want to deliver this to a client who will want to create their own - (void)authenticateUser method. 我们希望将此提供给想要创建自己的- (void)authenticateUser方法的客户端。 To do this I envisioned they would extend the UserManager class and just override the method. 为此,我设想他们将扩展UserManager类并只是覆盖该方法。

However as it is a singleton it has methods like: - (id)sharedInstance and a custom alloc method. 但是因为它是单例,所以它具有以下方法: - (id)sharedInstance和自定义alloc方法。 They all look like this: 他们都看起来像这样:

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;
}

So given this, is it possible to subclass and extend this UserManager class? 所以,鉴于此,是否可以UserManager和扩展此UserManager类? Can I create a ChildUserManager which overrides a function? 我可以创建一个覆盖函数的ChildUserManager吗? Or will I have to rewrite these singleton methods to deal with the "new" child class? 或者我是否必须重写这些单例方法来处理“新”子类?

Is there any way that I can modify these methods to make it so that 3rd parties can easily extend this class? 有什么方法可以修改这些方法,以便第三方可以轻松扩展这个类?

Thanks 谢谢

A better singleton pattern: 更好的单身人士模式:

// 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

If you subclass, the single instance will be set to whatever is called first, eg: 如果是子类,则单个实例将被设置为首先调用的任何内容,例如:

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

This alone would work tho: 仅这一点就可以了:

[[Cow sharedInstance]moo];

Beter design would be to use Composition then Inheritance. Beter设计将使用Composition然后继承。 Declare a protocol AuthenticationDelegate 声明协议AuthenticationDelegate

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

Have a property in UserManager that by default points to UserManager. 在UserManager中有一个属性,默认情况下指向UserManager。

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

@property (assign) id<AuthenticationDelegate>  authenticator

+ (id)sharedInstance;

Your clients if they want to authenticate by their method then they must confirm themselves to AuthenticationDelegate protocol and implement its methods. 如果您的客户希望通过他们的方法进行身份验证,那么他们必须向AuthenticationDelegate协议确认并实现其方法。 They must set authenticator property to their class that confines to . 他们必须将authenticator属性设置为其所限定的类。 However its singleton. 然而它的单身人士。 So they can set it as soon as their object is instantiated. 因此,只要对象被实例化,他们就可以设置它。 Hence they can use their Authenticator. 因此他们可以使用他们的身份验证器

But make it sure that authenticator dosent point to nil. 但要确保验证者剂量指向零。 You can implement the setAuthenticator: method so that authenticator will be pointing to UserManager when clients set this to nil. 您可以实现setAuthenticator:方法,以便当客户端将此设置为nil时,authenticator将指向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.
}

Hope this helps... 希望这可以帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM