简体   繁体   English

C# - 工厂模式如何使用反射?

[英]C# - Factory pattern using reflection or how?

I'm developing a game in console c#, that you can read maps created in files.我正在控制台 c# 中开发一款游戏,您可以读取在文件中创建的地图。 For doing so, i'm reading a file and storing that into a string.为此,我正在读取一个文件并将其存储到一个字符串中。 Then i'm reading each character individually and depending on the character, I need to create an object using the factory pattern.然后我单独读取每个字符并根据字符,我需要使用工厂模式创建一个 object。 I don't know how to do it without coupling the code.如果不耦合代码,我不知道该怎么做。

I have the main entity Object. From object inherit different objects, like: Box, Wall, Grass, Tree.我有主要实体 Object。从 object 继承不同的对象,如:盒子、墙、草、树。 Each one is represented by a character in the file and translated to another character in the game, (B)ox = '■', (W)all = '▓', (G)rass = 'v', (T)ree = '↑'.每一个都由文件中的一个字符表示并翻译成游戏中的另一个字符,(B)ox = '■', (W)all = '↓', (G)rass = 'v', (T)ree ='↑'。 The way I done that is by placing a property char "Model" in the Object with getter only, and in each object I override the getter with the corresponding model.我这样做的方法是在 Object 中放置一个属性字符“模型”,仅使用吸气剂,在每个 object 中,我用相应的 model 覆盖吸气剂。

Now, while I'm reading the file map mentioned before I need to tell the factory which object to build depending on the character read.现在,当我读取之前提到的文件 map 时,我需要根据读取的字符告诉工厂要构建哪个 object。 I dont want to make a big switch(character) because it will be coupled, because for each object I want to add I will have to add a new case in the switch.我不想做一个大开关(字符),因为它会耦合,因为对于每个我想添加的 object,我都必须在开关中添加一个新的案例。 Is any better way of doing so?有更好的方法吗?

Example of class Box: class 框示例:

public class Box : Object
{
    public override char Model { get { return '■'; } }

    public Box()
    {
        this.Name = "box";
        this.MapCharacter = 'B';
        this.Colors = new List<ConsoleColor>() { ConsoleColor.DarkYellow };
        this.Destructible = true;
        this.Passable = false;
        this.SeeThrough = false;
        this.Health = 200;
    }

    public override void OnDestroy()
    {
    }
}

Example code of Factory:工厂示例代码:

public class ObjectFactory : IObjectFactory
{
    public Object GetObject(char mapCharacter)
    {
        switch (mapCharacter)
        {
            case 'B':
                return new Box();
            case 'T':
                return new Tree();
            case 'W':
                return new Wall();
            case 'G':
                return new Grass();
            default:
                return null;
        }
    }
}

My idea was using Reflection get the Model of each class inherted from Object and somehow return that class, but that seems poor code我的想法是使用反射获取从 Object 继承的每个 class 的 Model 并以某种方式返回 class,但这似乎是糟糕的代码

There are pros and cons of going with reflection (personally I would not go this way in general case) but with current code you can improve it a bit and reduce the boilerplate by "converting" switch to dictionary:使用反射有利有弊(在一般情况下我个人不会 go 这种方式)但是使用当前代码你可以稍微改进它并通过“转换” switch到字典来减少样板:

public class ObjectFactory 
{
    private static readonly Dictionary<char, Func<MyObject>> _objectFactory = new Dictionary<char, Func<MyObject>>()
    {
        { 'B', () => new Box() },
        // ...
    };

    public Object GetObject(char mapCharacter)
    {
        if(_objectFactory.TryGetValue(mapCharacter, out var factory))
        {
            return factory();
        }

        return null;
    }
}

If you will decide that adding items to dictionary every time is to much - I would recommend to look into source generators , if this approach is to much - do not forget to "cache" the reflection.如果您决定每次都向字典添加项目太多了——我建议查看源代码生成器,如果这种方法太多了——不要忘记“缓存”反射。

It is worth to take a look Activator.CreateInstance method.值得一看Activator.CreateInstance方法。

If a map has full name of class, then it is possible to create an instance like this:如果 map 的全名是 class,则可以创建这样的实例:

public class InstanceHelper
{
    public static object Get(string fullyQualifiedName)
    {
        Type t = Type.GetType(fullyQualifiedName);
        return Activator.CreateInstance(t);
    }
}

So the above code can be called like this:所以上面的代码可以这样调用:

Box box = InstanceHelper.Get("Box") as Box;

You can use this code sample .您可以使用此代码示例 There is a class by name of EnhancedShapeFactory and it uses reflection.有一个名为EnhancedShapeFactory的 class,它使用反射。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM