Singleton and init with parameter

前端 未结 6 1358
孤街浪徒
孤街浪徒 2020-12-24 07:02

I want to use the singleton pattern in my class which has a private init with parameter. It also has a class function called setup which configures

6条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-24 07:25

    A literal translation of your Objective-C code might be:

    private var _asteroidSharedInstance: Asteroid!
    
    class Asteroid {
        private var config: ASTConfig?
    
        class func setup(config: ASTConfig) -> Asteroid {
            struct Static {
                static var onceToken: dispatch_once_t = 0
            }
            dispatch_once(&Static.onceToken) {
                _asteroidSharedInstance = Asteroid(config: config)
            }
            return _asteroidSharedInstance
        }
    
        class var sharedInstance: Asteroid! {                 // personally, I'd make this `Asteroid`, not `Asteroid!`, but this is up to you
            if _asteroidSharedInstance == nil {
                println("error: shared called before setup")
            }
    
            return _asteroidSharedInstance
        }
    
        init(config: ASTConfig) {
            self.config = config
        }
    }
    

    Or, in Swift 1.2, you could eliminate that Static struct and simplify setup a bit:

    private static var setupOnceToken: dispatch_once_t = 0
    
    class func setup(config: ASTConfig) -> Asteroid {
        dispatch_once(&setupOnceToken) {
            _asteroidSharedInstance = Asteroid(config: config)
        }
        return _asteroidSharedInstance
    }
    

    This really isn't a singleton. (I suspect you know this, but I mention that for the benefit of future readers). Typically singletons can be instantiated wherever and whenever they're first used. This is a scenario where it's being instantiated and configured in only one particular place and you must take care to do this before you try to use it elsewhere. That's very curious approach. We lose some singleton functionality, but still suffer all of the traditional singleton limitations.

    Clearly, if you're ok with that, that's fine. But if you're entertaining alternatives, two jump out at me:

    1. Make this real singleton: You can accomplish this (eliminating the dependency of having to call setup before you use sharedInstance) by moving the instantiation of the ASTConfig inside the init method. Then you can retire setup and just use your singleton like normal. The resulting implementation is greatly simplified, too. It gets reduced down to something like:

      class Asteroid {
          static let sharedInstance = Asteroid()
      
          private let config: ASTConfig
      
          init() {
              self.config = ASTConfig(...)
          }
      }
      

      Clearly, I suspect the devil is in the details of that ASTConfig object, but if you can do a proper singleton implementation, as you can see this is much simpler (esp. in Swift 1.2). And the above eliminates the setup vs sharedInstance problem. Eliminates the private global. Just simpler all the way around.

      Having said that, I assume you had compelling reasons to do it the way you did. Perhaps there is some critical reason why you must pass ASTConfig object to setup method rather than just instantiating it yourself within the init of the Asteroid class.

      I just felt obliged to point out that a proper singleton would be greatly preferable (both much simpler implementation and eliminates theoretical race conditions).

    2. Abandon singleton pattern entirely: Assuming using a proper singleton, as outlined above, is not possible, the next question is whether you should just abandon any remaining semblance of a singleton, just instantiate a simple Asteroid where you are currently calling setup, and then rather than relying upon sharedInstance, just pass it to the objects that really need it.

      You already have specified that you're going to manually setup the Asteroid up front, so let's formalize that relationship and eliminate many of the structural flaws that singletons introduce (see What's Alternative to Singleton or google "singletons are evil").

    Don't get me wrong. I assume that you have compelling reasons to do it the way you have, and if the current implementation works for you, that's fine. But this is a very curious approach, in which you're encumbered with the theoretical liability of singletons without enjoying all the benefits.

提交回复
热议问题