工厂根据字符串创建AND实例化对象?

时间:2013-02-13 11:13:34

标签: c# reflection factory-pattern

我有一个从队列中读取字符串消息并“处理它们”的请求。每条消息都有一个4位“标识符/密钥”作为开头,后跟日期,时间和另一个数字......从那时起,每条消息都不同,需要不同的处理。

我的想法是使用工厂创建所需类型的对象,并同时调用asbtract构造函数。

这是一种明智的做法吗? 如果是这样......怎么样?

e.g。

1000,2013-02-13,09:00:00,492,....................
4000,2013-02-13,09:00:01,492,....................
1000,2013-02-13,09:00:02,74664,....................
4003,2013-02-13,09:00:03,1010,....................
4000,2013-02-13,09:00:04,493,....................

构建类的对象

Message1000 : AbstractMessage, IMessageThing
Message4000 : AbstractMessage, IMessageThing
Message4003 : AbstractMessage, IMessageThing

AbstractMessage包含默认构造函数以及键,日期,时间,数字等属性。

4 个答案:

答案 0 :(得分:1)

是的,你可以而且是一种正确而明智的方法。如果您可以拥有默认构造函数,那么事情会发生一些变化,如果构造函数与一个具体实现不同,那么它也会发生变化。最简单的方法是使用无参数构造函数。 有了这个先决条件,你可以这样:

Type t = Type.GetType(string.Format("Handlers.MyHandlers.Message{0}",messageType));
var handler = Activator.CreateInstance(t) as IMessageThing;

为了将字符串传递给消息,您可以在IMessageThing界面中定义一个函数,让我们在创建消息后立即调用它Init,或者可能更好,一个costructor在AbstractMessage类中取一个字符串,然后像这样在激活器中调用它:

var handler = Activator.CreateInstance(t,body) as IMessageThing;

AbstractMessage的构造函数中调用 abstract 函数Init(string body),因此每个具体消息都需要实现自己的解析器。

添加更多错误处理,您已完成。

答案 1 :(得分:1)

如果有意义取决于您的要求。

您可以像这样分析字符串:

// inside your actual factoryMethod...
var lines = ...;

foreach(var line in lines)
{
    var tokens = line.Split(',');
    // for split: you can also specify the max. amount of items if the ..... part can
    // consist of more the dots.

    CreateMessageObject(tokens); // eventually add to list of AbstractMessage or whatever
}



static FactoryClassConstructor()
{
     _typeMap = new Dictionary<string, Type>();
     _typeMap.Add("Message1000", typeof(Message1000));
     // todo: add other message types
     // you also could write a method which will use the class name of the 
     // type returned by typeof(XYZ) to assure the correct value as key
}

private Dictionary<string, Type> _typeMap;

private AbstractMessage CreateMessageObject(string[] tokens)
{
    // simple error checking
    if(tokens.Count != 5)
        // todo: error handling
        return null;

    var type = typeMap[tokens[0]];
    var instance = Activator.CreateInstance(type);

    instance.Date = DateTime.Parse(tokens[1]);
    instance.Time = DateTime.Parse(tokens[2]);
    // todo initialize other properties
}

当然你还需要做一些错误处理,但我希望我能给你一个很好的起点。

我之所以使用字典是因为性能。 Activator.CreateInstance不是很快,使用Type.GetType的查找也很慢。 您可以使用以下内容:

,而不是在字典中使用类型作为值
Dictionary<string, Action<IMessageThing>> _factories;
_factories = new Dictionary<string, Action<IMessageThing>>();
_factories.Add("Message1000", () => new Message1000());

并创建您可以调用的对象:

var instance = _factories["Message1000"]();

答案 2 :(得分:0)

一种方法是将字符串拆分为,,但将最大计数设置为5,这应该将所有值组合在一个值之后作为一个值:

var parts = your_string.split(new char[] {','},5);

然后您只需使用Activator.CreateInstance()来创建消息实例。例如:

Type type = Type.GetType(String.Format("Message{0}",parts[0]));
var instance = Activator.CreateInstance(type) as IMessageThing;

然后,您可以从parts填写其余属性。

答案 3 :(得分:0)

您可以将每条消息传递给处理程序,处理程序将检查它是否可以处理此类消息。如果是这样,它将解析并返回一些对象,否则它将返回例如null,你会知道问一个不同的处理程序。

或者构建一个解析器,它知道遵循通用格式的初始部分,然后使用查找表来查找将解析剩余消息并实例化正确类型的特定消息处理程序。 (将公共部分传递给它的构造函数)。

我不明白你的意思是“创建一个所需类型的对象,并且还调用asbtract构造函数”。没有抽象构造函数这样的东西。如果您指的是抽象基类的构造函数,则在实例化子类时,它将不可避免地被调用。