簡體   English   中英

使用反射的工廠模式-使用與每個類關聯的靜態鍵進行類注冊

[英]Factory pattern using reflection - class registration using static key associated with each class

在研究一些模式時,我遇到了工廠模式以創建(未知)類的實例。 這使我產生了興趣,因此我想構建一個可以動態增強的程序。 因此,我在一個程序集中具有一些基本功能,而在不同程序集中具有實際工人。 我從應用程序獲得的唯一提示是操作名稱。 現在,我想創建一個依賴於該操作的新工作程序。 因為我不知道這些工人的實際實現方式,所以選擇了這種模式。

OK,更多細節:

我的所有流程都實現了一個IWorker Singleton WorkerFactory使我可以在與當前組件相同的路徑中的任何程序WorkerFactory創建實現的任何worker的新實例。 為此,我在接口中添加了一個CreateWorker方法,該方法接受一個字符串數組(這些字符串已作為varargs傳遞到控制台應用程序)。

在能夠創建任何工人的任何實例之前,我必須向工廠注冊任何類。 不幸的是,在C#上,無法將這種行為靜態地插入到工作者類的任何靜態上下文中,因為僅當以任何方式訪問該類時(無論是通過實例化它還是通過訪問任何一個此類),都將執行此上下文中的代碼其靜態成員,請參見靜態構造函數 )。 因此,我通過用當前正在執行的程序集的路徑反映所有程序集內找到的所有類型來實現這一點。 現在,我可以檢查當前類型是否正在實現該接口,如果可以,則可以將該類型作為System.Type添加到包含操作名稱(鍵)和worker(值)的工廠的注冊映射中(請參閱使用反射 )。 問題是:如何獲取此類型所指操作的實際名稱。

我認為有兩種選擇:

  1. 我向存儲操作名稱的每個工人類添加一個靜態屬性。 因此,我可以通過在獲得的類型上反映此屬性來引用該操作。
  2. 為該名稱添加一個非靜態屬性,並在注冊時創建實際工作人員類的虛擬實例。

盡管前者的缺點是我無法確保所有工作程序實際上都實現了這樣的靜態屬性(因此無法向IWorker接口添加靜態成員),但后者的缺點是每個類都必須有一個空構造函數,以構建從中獲取操作名稱的虛擬實例。 但是,此構造函數將可以公開訪問,同時不包含任何初始化代碼。

話雖如此,所有這些問題都是關於使用反射的工廠模式的最佳實踐,或者至少是最佳實踐。 我認為我更喜歡第一種選擇,但是也許我也錯過了這種方法的任何更好的解決方案。

因此,該線程已經很長了,我不想在這里發布任何代碼,但是無論如何請告訴我。

您可以在工作程序類上使用自定義屬性

[AttributeUsage(System.AttributeTargets.Class)]
public class WorkerAttribute : Attribute
{
    public WorkerAttribute (String operationType)
    {
       this.OperationType = operationType; 
    }

    public String OperationType {get; private set;}
}

public interface IWorker { }

[WorkerAttribute("Experienced")]
public class ExperiencedWorker: IWorker
{
}

可以按此處所述訪問它們。 它將類似於:

       Type attributeType = typeof(WorkerAttribute);

        var myWorkerClassesPlusAttributes = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                            from type in assembly.GetTypes()
                                            let attributes = type.GetCustomAttributes(attributeType, true)
                                            where attributes.Any()
                                            select 
                                                new KeyValuePair<String, Type>(((WorkerAttribute)attributes.First()).OperationType, 
                                                                               type);

        Dictionary<String, Type> workers = new Dictionary<string, Type>();
        foreach (var item in myWorkerClassesPlusAttributes)
            workers.Add(item.Key, item.Value);

        IWorker worker = (IWorker)Activator.CreateInstance(workers["Experienced"]);

它不是最好的,並且不包含該類上的多個WorkerAttributes,但可以用作解決方案的基礎。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM