2014-11-12 2 views
1

Ищете рекомендации по дизайну для следующей проблемы. Я получаю два строковых значения - действие и сообщение и должен вызвать соответствующий метод, который обрабатывает строковое сообщение (processM1MessageVer1, processM1MessageVer2, processM2MessageVer1 ...). Метод, который я должен вызывать, зависит от заданного строкового действия. Существует 2 версии (но в будущем может быть больше) каждого метода обработки. Версия метода, который я должен вызывать, определяется глобальной версией. Каждый метод возвращает объект другого типа (ResultObject1, ResultObject2 ...). Результат должен быть сериализован, преобразован в base64 и возвращен обратно.Руководство по проектированию C# - вызов соответствующего метода на основе значения строки

Есть ли более элегантный способ написания этого (исключить дублирование кода, сделать возможным в будущем изменения легче, уменьшить код ...):

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; 
    } 

Было бы проще, если сообщения, которые должны быть обработаны, имеют различные типы объектов вместо строк, так что соответствующий метод можно было бы назвать полиморфно. Тот факт, что каждый метод процесса возвращает другой тип объекта, также усложняет ситуацию. Но это не зависит от меня, и я не могу его изменить.

+1

Используя переключатель отлично и эффективная производительность. Если вы знаете во время компиляции все возможности, это неплохой путь. В некоторых случаях люди могут предпочесть словарь, например. 'Словарь >' в вашем случае, где он заполнен ключами (то есть, что в противном случае было бы метками 'case') и' делегатами делегирования 'Func '' для методов, которые выполняют соответствующую обработку (т.е. взять «сообщение» и получить результат «результат»). Это не будет работать лучше, чем 'switch', но в качестве предпочтения некоторым может понравиться это лучше. –

ответ

1

Мой подход (сделать его более ориентированным на объекты, и вы должны обосновать, целесообразно ли создавать структуру класса в зависимости от того, насколько сложна ваша логика обработки. Если ваша логика обработки мало, возможно, это чрезмерная инженерия):

Для сериализации и преобразования в базу 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); 

Выключатель по-прежнему существует на заводе класса, но это только возвращает процессор и не делает фактическую работу, так что это нормально для мне

0

Первый - определить интерфейс, который подойдет вам лучше всего, как этот

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); 
    } 
}