2017-04-21 59 views
6

我有一個簡單的服務管理器,名爲ServiceManager,它有兩種方法。 Create()創建一個服務的實例。 Provide()返回以前創建的服務。從類型和實例字典中獲取實例

我有一個基本的實現,但我想知道是否有一個更清潔的方式。這是我的基本實現ServiceManager的:

public class ServiceManager : MonoBehaviour 
{ 
    private Dictionary<Type, MonoBehaviour> services = new Dictionary<Type, MonoBehaviour>(); 

    public void Create<T>() where T : MonoBehaviour 
    { 
     // Create service 
     GameObject serviceObject = new GameObject(typeof(T).Name); 
     serviceObject.transform.SetParent(transform); // make service GO our child 
     T service = serviceObject.AddComponent<T>(); // attach service to GO 

     // Register service 
     services.Add(typeof(T), service); 
    } 

    public T Provide<T>() where T : MonoBehaviour 
    { 
     return (T)services[typeof(T)]; // notice the cast to T here 
    } 
} 

使用該服務很簡單:

public class ServiceTest : MonoBehaviour 
{ 
    private void Start() 
    { 
     // Creating services 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     services.Create<MapService>(); 
     services.Create<InteractionService>(); 
    } 

    private void Example() 
    { 
     // Get a service 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     MapService map = services.Provide<MapService>(); 
     // do whatever you want with map 
    } 
} 

我的問題是關於ServiceManager.Provide()。從字典中獲取項目後,注意將其轉換爲T.這種感覺非常不潔,讓我懷疑我是否錯過了泛型在C#中的工作原理。還有其他/更好的方法去做我想要完成的事情嗎?

+1

*「這感覺非常不潔」* - 對我來說不是這樣。對我來說它看起來很好。泛型不會在那裏爲你做任何魔術。這是一個演員;他們不是偶然的語言。你很好。 –

+0

@EdPlunkett好的,謝謝!只是想確保沒有我不瞭解的東西。乾杯。 –

回答

3

這裏沒有什麼好改進的。因爲字典值類型是MonoBehaviour,所以強制轉換是必需的。 知道它實際上是T,但編譯器沒有。你必須通過鑄造來說明。

你做得很好。

+0

謝謝你的解釋!我只是想確保我沒有忽略任何東西。乾杯。 –

+0

我認爲如果每個類型只有一個實例出現,那麼它比帶有強制轉換的字典更好。看到我的答案。 –

1

如果每種類型只有一個實例,那就更好了。考慮靜態泛型類型

using UnityEngine; 

public class ServiceManager : MonoBehaviour 
{ 
    // If this T confuses you from the generic T used elsewhere, rename it 
    public static Transform T { get; private set; } 

    void Awake() 
    { 
     T = transform; 
    } 

    public T Provide<T>() where T : MonoBehaviour 
    { 
     return ServiceMap<T>.service; // no cast required 
    } 
} 

static class ServiceMap<T> where T : MonoBehaviour 
{ 
    public static readonly T service; 

    static ServiceMap() 
    { 
     // Create service 
     GameObject serviceObject = new GameObject(typeof(T).Name); 
     serviceObject.transform.SetParent(ServiceManager.T); // make service GO our child 
     service = serviceObject.AddComponent<T>(); // attach service to GO 
    } 
} 

使用該服務很簡單:

public class ServiceTest : MonoBehaviour 
{ 
    private void Start() 
    { 
     // no need to Create services 
     // They will be created when Provide is first called on them 
     // Though if you want them up and running at Start, call Provide 
     // on each here. 
    } 

    private void Example() 
    { 
     // Get a service 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     MapService map = services.Provide<MapService>(); 
     // do whatever you want with map 
    } 
} 

此外,如果你有多個ServiceManagers那麼這將無法工作。