0

我有一个通用格式的文本文件:

ThreadID, MethodName, [Param1 | Param2 | ... ]

我有一个实用程序类,如下所示:

public static class Util
{
    public static List<double> Foo(List<double> Source, double Scale)
    {
        List<double> l = new List<double>(Source);
        for (int i = 0; i < l.Count; i++)
        {
            l[i] = l[i] * Scale;
        }
        return l;
    }

    public static void Fud(List<double> Source, string Name)
    {
        //... Chart Series
    }
    public static bool Fee(CustomClass MyClass, double Limit1, int Limit2)
    {
        //... Test MyClass values against input limits
        return true; // false;
    }
}

所以我使用了一个开关/案例,它给出了文本文件中的方法名称,然后解析并将参数传递给案例中的方法。sudo 代码的效果是:

    static void Main(string[] args)
    {
        List<string> TextFile;
        List<double>[] Register = new List<double>[3];   //lists containing data that is moved, mutated and converted to CustomClass
        CustomClass MyClass = new CustomClass();
        bool Passed = false;

        foreach (var line in TextFile)
        {
            string methodName = Util.ParseMethod(line);          //parsed from file
            string param1, param2, param3, param4 = Util.ParseParams(line);          //parsed from file
            switch (methodName)
            {
                case "Foo":
                    Register[param1] = Util.Foo(Register[param2], param3);
                    break;

                case "Fud":
                    Util.Fud(Register[param1], param3);
                    break;

                case "Fee":
                    Passed = Util.Foo(MyClass, param1, param2);
                    break;
            }
        }
    }

我不喜欢拆分逻辑,每次开发新的实用程序方法时,我都必须手动添加另一个案例语句。case 语句变得难以维护,因为设计时错误(字符串/更新中的拼写错误)通常只在运行时被捕获。

我试图将这一切转换为工厂架构,但我似乎无法适应不同的方法定义。我希望取消 Utility 类并使用工厂接口在它自己的类中定义每个方法。

public interface IRecipe
{
    string GetFactoryKey();
    string SerializeArgs(object[] args);
    object[] DeserializeArgs(string args);
    ??? DoWork(???);
}

问题是由于实用程序类中的每个方法有多么不同,我找不到在接口中正确定义它的方法。我想要的最终结果是我可以用通用代码替换 foreach 循环中的开关,并且在实现工厂接口而不是方法调用者的每个类中定义所有细节逻辑、解析、方法定义、错误检查和验证. 我已经用完了谷歌的东西,因为我什至不知道我想要做什么。

4

2 回答 2

0

我想我想通了……这是我迄今为止的完整概念证明。还是有点丑,但我至少把丑封装在了每个工厂类里。这意味着 Main 中的调用者可以保持非常通用,以便在循环中轻松使用。当我做真正的实现时,我会更多地重构它。

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            List<double>[] Reg = new List<double>[2]; for (int i = 0; i < Reg.Length; i++) { Reg[i] = new List<double>(); }

            for (int i = 0; i < 100; i++)
            { Reg[1].Add(1.0); }            //Dummy data

            var obj = ClassFactory.CreateStep("AmplifySignal");
            object[] Args = obj.DeserializeProperties(" ");
            Args[0] = Reg;
            dynamic result = obj.Run(Args);

            if (result != null)
            { Thread.Sleep(0); }    //breakpoint

            Console.ReadKey();
        }
    }

    internal static class ClassFactory
    {
        private static readonly IDictionary<String, Type> _recipe_instructions;

        static ClassFactory() { _recipe_instructions = MapIFactory(); }

        private static IDictionary<string, Type> MapIFactory()
        {
            // Get the assembly that contains this code
            Assembly asm = Assembly.GetExecutingAssembly();

            // Get a list of all the types in the assembly
            Type[] allTypes = asm.GetTypes();

            var d = new Dictionary<string, Type>();
            foreach (var type in allTypes)
            {
                if (type.IsClass && !type.IsAbstract && type.GetInterface(typeof(IFactory).ToString()) != null)
                {
                    // Create a temporary instance of that class...
                    object inst = asm.CreateInstance(type.FullName, true, BindingFlags.CreateInstance, null, null, null, null);
                    if (inst != null)
                    {
                        // And generate the product classes key
                        IFactory mapKey = (IFactory)inst;
                        object key = mapKey.GetFactoryKey();
                        inst = null;

                        //Add the results to a Dictionary with the Name as a key and the Type as the value
                        d.Add((string)key, type);
                    }
                }
            }
            return d;
        }

        internal static IFactory CreateStep(String key)
        {
            Type type;
            if (_recipe_instructions.TryGetValue(key, out type))
            { return (IFactory)Activator.CreateInstance(type); }
            throw new ArgumentException(String.Format("Unable to locate key: {0}", key));
        }
    }

    public interface IFactory
    {
        string GetFactoryKey();
        string SerializeProperties();
        object[] DeserializeProperties(string args);
        dynamic Run(params object[] args);
    }

    public class AmplifySignal : IFactory
    {
        public string GetFactoryKey()
        { return MethodBase.GetCurrentMethod().DeclaringType.Name; }
        public object[] DeserializeProperties(string args)
        { return new object[] { null, (int)1, (double)2.1 }; }
        public string SerializeProperties()
        { return " 1 | 2.1 "; }

        public dynamic Run(params object[] args)
        {
            // Build Inputs
            List<double>[] registers = (List<double>[])args[0];
            List<double> waveform = (List<double>)registers[(int)args[1]];
            double factor = (double)args[2];

            // Do Work
            double[] Result = waveform.ToArray();      //Localize and Deep Copy
            for (int i = 0; i < Result.Length; i++)
            { Result[i] *= factor; }
            List<double> result = Result.ToList();    //breakpoint

            // Write Result
            return result;
        }
    }
}

如果我在这里做了一些真正亵渎神明的事情,并且有更好的方法来完成同样的事情,那么我无论如何都愿意接受建议。我会等待一两天,然后才能接受这个答案,以便提供任何反馈。

于 2013-01-03T23:23:22.950 回答
0

如果 DoWork 方法采用单个字符串参数(逗号分隔的参数)并根据需要将其拆分怎么办?然后您仍然可以使用简单的界面并将详细信息留给每个配方。

另一种选择是将字符串数组作为参数,类似于将工作分拆到新线程中的方式(指定要调用的方法和包含其参数的数组。)

于 2013-01-03T19:49:14.260 回答