2016-02-19 48 views
2

我定義的全局結構與靜態屬性與我在我的許多視圖控制器的使用值,如:替代Swift中的臭味全局變量?

public struct AppGlobal { 
    static var currentUser = UserModel() 
    static let someManager = SomeManager() 

    // Prevent others from initializing 
    private init() { } 
} 

然後在我的UIViewController,我可以做這樣的事情:

class MyController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     AppGlobal.currentUser.prop1 = "abc123" 
     AppGlobal.someManager.startUpdating() 
    } 
} 

這顯然很方便,但味道真的很差。我相信依賴注入會派上用場,但不知道如何。有創建AppGlobal單身人士屬性更優雅的替代方案嗎?

+0

我通常使用我的管理類的單例實例,它仍然存在「全局方法」的問題,但許多API使用相同的技術,我認爲這些案例是最好的。 – UlyssesR

回答

5

我看不出爲什麼你需要通過全局狀態訪問userModel或someManager(是的 - 單身人士就是這樣)。

爲什麼不把它設置在你需要的地方?

「依賴注入」是一個5美元概念的25美元術語。 這並不是說這是一個壞詞...

依賴注入意味着 給一個對象的實例變量。真。而已。

- 詹姆斯岸:Dependency Injection Demystified

無論是構建

class C { 
    let currentUser: UserModel 
    let someManager: SomeManager 
    init(currentUser:UserModel, someManger:SomeManager) { 
     self.currentUser = currentUser 
     self.someManager = someManager 
    } 
} 

或通過屬性時做到這一點。如果您需要確保所有屬性都設置,做這樣的事情:

class MyController: UIViewController { 
    var currentUser: UserModel? { 
     didSet{ 
      self.configureIfPossible() 
     } 
    } 
    var someManager: SomeManager?{ 
     didSet{ 
      self.configureIfPossible() 
     } 
    } 

    func configureIfPossible(){ 
     if let currentUser = self.currentUser, someManager = self.someManager { 
      // configure  
     } 
    } 
} 

在我目前的項目,我們有,每一個依賴必須從類的外部可見的和可配置的策略。

一個例子:

class LibrarySegmentViewController: BaseContentViewController { 
    var userDefaults: NSUserDefaults? 
    var previousSorting : LibrarySortingOrder = .AZ 
    var sorting : LibrarySortingOrder { 
     set{ 
      self.previousSorting = sorting 
      if let filterMode = self.filterMode { 
       self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting") 
      } 
      self.setupIfReady() 
     } 
     get{ 
      if let filterMode = self.filterMode { 
       if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) { 
        return s 
       } 
      } 
      return .Date 
     } 
    } 

} 

所以你可以看到,我們甚至使用屬性引用NSUserDefaults.standardUserDefaults()。我們這樣做是因爲我們可以在測試過程中通過新的實例,而不會有更大的嘲諷麻煩。

這是爲什麼不直接使用singleton的最主要原因:依賴關係是隱藏的,在測試和重構過程中可能會咬你。另一個例子是一個隱藏在代碼中的API客戶端單例,在測試過程中執行不需要的聯網請求。如果它是從被測試類之外設置的,則可以傳入一個模擬網絡客戶端,該客戶端不會執行任何請求,但會返回測試數據。

所以即使你使用單例,你也應該把它作爲一個依賴關係傳入。

+0

這應該是正確的答案。依賴注入使得你的代碼更具可測性,因爲它使得你的依賴可以被替換和嘲弄。單身人士是反模式。它們導致緊密的耦合,這使得你的代碼不易測試。 – pommes

3

如果這個問題是關於全球與否,你應該看到這個線程: What is so bad about singletons?

但是,如果你想要一個更好的設計爲您實現一個單身的你可以嘗試這樣的事:

class SingletonExample: NSObject { 

    static let sharedInstance: SingletonExample() 
} 

class OtherSingletonExample: NSObject { 

    static let sharedInstance: OtherSingletonExample() 
} 

然後,您可以在代碼中的任意位置使用SingletonExample.sharedInstanceOtherSingletonExample.sharedInstance

這個想法是將一個單例從另一個單例中分離出來,並以類屬性的形式訪問它,而不是爲任何東西創建一個大的全局結構。