繁体   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