【问题标题】:C# design guideline - calling appropriate method based on string valueC# 设计指南 - 基于字符串值调用适当的方法
【发布时间】:2014-11-12 00:00:03
【问题描述】:

寻找以下问题的设计指南。 我收到两个字符串值 - 操作和消息,并且必须调用处理字符串消息的适当方法(processM1MessageVer1、processM1MessageVer2、processM2MessageVer1 ...)。我必须调用的方法取决于给定的字符串操作。每种处理方法都有 2 个版本(但将来可能会有更多)。我必须调用的方法版本由全局变量版本决定。每个方法都返回不同类型的对象(ResultObject1、ResultObject2 ...)。结果必须被序列化,转换为base64并返回。

有没有更优雅的写法(消除重复代码,使未来可能的更改更容易,减少代码......):

    string  usingVersion = "ver1";
    public string processRequest(string action, string message)
        if (usingVersion == "ver1"){
            processRequestVer1(action, message);
        }
        else{
            processRequestVer2(action, message);
        }
    }    

    //version 1
    public string processRequestVer1(string action, string message){
        string result = "";
        switch (action){
            case "m1":
                ResultObject1 ro = processM1MessageVer1(message);
                result = serialize(ro);
                result = convertToB64(result);
            case "m2":
                ResultObject2 ro = processM2MessageVer1(message);
                result = serialize(ro);
                result = convertToB64(result);
            case "m3":
                ResultObject3 ro = processM3MessageVer1(message);
                result = serialize(ro);
                result = convertToB64(result);      
        }
        return result;
    }

    //version 2
    public string processRequestVer2(string action, string message){
        string result = "";
        switch (action){
            case "m1":
                ResultObject1 ro = processM1MessageVer2(message);
                result = serialize(ro);
                result = convertToB64(result);
            case "m2":
                ResultObject2 ro = processM2MessageVer2(message);
                result = serialize(ro);
                result = convertToB64(result);
            case "m3":
                ResultObject3 ro = processM3MessageVer2(message);
                result = serialize(ro);
                result = convertToB64(result);      
        }
        return result;
    }

如果必须处理的消息是不同的对象类型而不是字符串,这样会更简单,以便可以多态地调用适当的方法。每个流程方法返回不同对象类型的事实也使事情变得更加复杂。但这些不取决于我,我无法改变。

【问题讨论】:

  • 使用开关在性能方面很好且高效。如果您在编译时知道所有可能性,那么这不是一个坏方法。在某些情况下,人们可能更喜欢字典,例如Dictionary<string, Func<string, string>> 在您的情况下,它填充了键(即否则将是 case 标签)和 Func<T, TResult> 委托实例用于进行适当处理的方法(即采用 message 并导致 @987654326 @)。这不会比switch 表现更好,但根据偏好,有些人可能更喜欢它。

标签: c# oop


【解决方案1】:

我的方法(使其更加面向对象,并且您应该根据处理逻辑的复杂程度来证明创建类结构是否合适。如果您的处理逻辑很少,那么这可能是过度工程):

对于序列化并转换为 base 64,我假设您有一些逻辑可以以通用方式完成这些任务。如果没有,也将它们移至子类

 public interface IRequestProcessorFactory
{
    IRequestProcessor GetProcessor(string action);
}

public class FactoryVersion1 : IRequestProcessorFactory
{
    public IRequestProcessor GetProcessor(string action)
    {
        switch(action)
        {
            case "m1":
                return new M1Ver1RequestProcessor();
            case "m2":
                return new M2Ver1RequestProcessor();
            case "m3":
                return new M3Ver1RequestProcessor();
            default:
                throw new NotSupportedException();
        }
    }
}

public class FactoryVersion2 : IRequestProcessorFactory
{
    public IRequestProcessor GetProcessor(string action)
    {
        switch(action)
        {
            case "m1":
                return new M1Ver2RequestProcessor();
            case "m2":
                return new M2Ver2RequestProcessor();
            case "m3":
                return new M3Ver2RequestProcessor();
            default:
                throw new NotSupportedException();
        }
    }
}

public interface IRequestProcessor
{
    string ProcessRequest(string message);
}

public class RequestProcessorBase<T>
{
    public string ProcessRequest(string message)
    {
        T result = Process(message);
        string serializedResult = Serialize(result);
        return ConvertToB64(serializedResult);
    }

    protected abstract T Process(string message);

    private string Serialize(T result)
    {
        //Serialize
    }

    private string ConvertToB64(string serializedResult)
    {
        //Convert
    }
}

public class M1Ver1RequestProcessor : RequestProcessorBase<ResultObject1>
{
    protected ResultObject1 Process(string message)
    {
        //processing
    }
}

public class M2Ver1RequestProcessor : RequestProcessorBase<ResultObject2>
{
    protected ResultObject2 Process(string message)
    {
        //processing
    }
}

public class M3Ver1RequestProcessor : RequestProcessorBase<ResultObject3>
{
    protected ResultObject3 Process(string message)
    {
        //processing
    }
}

public class M1Ver2RequestProcessor : RequestProcessorBase<ResultObject1>
{
    protected ResultObject1 Process(string message)
    {
        //processing
    }
}

public class M2Ver2RequestProcessor : RequestProcessorBase<ResultObject2>
{
    protected ResultObject2 Process(string message)
    {
        //processing
    }
}

public class M3Ver2RequestProcessor : RequestProcessorBase<ResultObject3>
{
    protected ResultObject3 Process(string message)
    {
        //processing
    }
}

用法:

string action = "...";
string message = "...";
IRequestProcessorFactory factory = new FactoryVersion1();
IRequestProcessor processor = factory.GetProcessor(action);
string result = processor.ProcessRequest(message);

工厂类中的开关仍然存在,但它只返回处理器,不做实际工作,所以对我来说没问题

【讨论】:

    【解决方案2】:

    首先 - 定义最适合你的界面,像这样

        public interface IProcessMessage
        {
            string ActionVersion { get; }
            string AlgorithmVersion { get; }
            string ProcessMessage(string message);
        }
    

    然后根据需要创建尽可能多的实现

    public class processorM1Ver1 : IProcessMessage
    {
        public string ProcessMessage(string message)
        {
            ResultObject1 ro1 = processM1MessageVer1(message);
            var result = serialize(ro1);
            result = convertToB64(result);
            return result;
        }
    
        public string ActionVersion {get { return "m1"; }}
    
        public string AlgorithmVersion {get { return "ver1"; }}
    }
    
    public class processorM2Ver1 : IProcessMessage
    {
        public string ActionVersion {get { return "m2"; }}
    
        public string AlgorithmVersion {get { return "ver1"; }}
    
        public string ProcessMessage(string message)
        {
            ResultObject1 ro1 = processM2MessageVer1(message);
            var result = serialize(ro1);
            result = convertToB64(result);
            return result;
        }
    }
    
    public class processorM1Ver2 : IProcessMessage
    {
        public string ActionVersion {get { return "m1"; }}
    
        public string AlgorithmVersion {get { return "ver2"; }}
    
        public string ProcessMessage(string message)
        {
            ResultObject1 ro1 = processM1MessageVer2(message);
            var result = serialize(ro1);
            result = convertToB64(result);
            return result;
        }
    }
    

    现在您需要知道在当前上下文中哪种实现最好的东西

    public class MessageProcessorFactory
    {
        private MessageProcessorFactory() { }
        private static readonly MessageProcessorFactory _instance = new MessageProcessorFactory();
        public static MessageProcessorFactory Instance { get { return _instance; }}
    
        private IEnumerable<IProcessMessage> _processorCollection;
        IEnumerable<IProcessMessage> ProcessorCollection
        {
            get
            {
                if (_processorCollection == null)
                {
                    //use reflection to find all imlementation of IProcessMessage
                    //or initialize it manualy
                    _processorCollection = new List<IProcessMessage>()
                    {
                        new processorM1Ver1(),
                        new processorM2Ver1(),
                        new processorM1Ver2()
                    };
                }
                return _processorCollection;
            }
        } 
    
        internal IProcessMessage GetProcessor(string action)
        {
            var algorithVersion = ReadAlgorithVersion();
            var processor = ProcessorCollection.FirstOrDefault(x => x.AlgorithmVersion == algorithVersion && x.ActionVersion == action);
            return processor;
        }
    
        private string ReadAlgorithVersion()
        {
            //read from config file
            //or from database
            //or where this info it is kept
            return "ver1";
        }
    }
    

    可以这样使用

    public class Client
    {
        public string ProcessRequest(string action, string message)
        {
            IProcessMessage processor = MessageProcessorFactory.Instance.GetProcessor(action);
            return processor.ProcessMessage(message);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多