Что-то, что встречается довольно часто в моей текущей работе, заключается в том, что существует обобщенный процесс, который должен произойти, но тогда нечетная часть этого процесса должна происходить немного по-другому, в зависимости от значения определенной переменной, и яЯ не совсем уверен, каков самый элегантный способ справиться с этим.
Я буду использовать пример, который у нас обычно есть, который делает вещи немного по-разному в зависимости от страны, с которой мы имеем дело.
Итак, у меня есть класс, назовем его Processor
:
public class Processor
{
public string Process(string country, string text)
{
text.Capitalise();
text.RemovePunctuation();
text.Replace("é", "e");
var split = text.Split(",");
string.Join("|", split);
}
}
За исключением того, что для некоторых стран должны выполняться только некоторые из этих действий. Например, только 6 стран требуют шага капитализации. Персонаж для разделения может меняться в зависимости от страны. Замена акцентированного 'e'
может потребоваться только в зависимости от страны.
Очевидно, вы можете решить эту проблему, выполнив что-то вроде этого:
public string Process(string country, string text)
{
if (country == "USA" || country == "GBR")
{
text.Capitalise();
}
if (country == "DEU")
{
text.RemovePunctuation();
}
if (country != "FRA")
{
text.Replace("é", "e");
}
var separator = DetermineSeparator(country);
var split = text.Split(separator);
string.Join("|", split);
}
Но когда вы имеете дело со всемивозможные страны в мире, это становится очень громоздким. И, тем не менее, операторы if
затрудняют чтение логики (по крайней мере, если вы представите более сложный метод, чем в примере), и цикломатическая сложность начинает довольно быстро нарастать.
Так что нав тот момент, когда я делаю что-то вроде этого:
public class Processor
{
CountrySpecificHandlerFactory handlerFactory;
public Processor(CountrySpecificHandlerFactory handlerFactory)
{
this.handlerFactory = handlerFactory;
}
public string Process(string country, string text)
{
var handlers = this.handlerFactory.CreateHandlers(country);
handlers.Capitalier.Capitalise(text);
handlers.PunctuationHandler.RemovePunctuation(text);
handlers.SpecialCharacterHandler.ReplaceSpecialCharacters(text);
var separator = handlers.SeparatorHandler.DetermineSeparator();
var split = text.Split(separator);
string.Join("|", split);
}
}
Обработчики:
public class CountrySpecificHandlerFactory
{
private static IDictionary<string, ICapitaliser> capitaliserDictionary
= new Dictionary<string, ICapitaliser>
{
{ "USA", new Capitaliser() },
{ "GBR", new Capitaliser() },
{ "FRA", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
{ "DEU", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
};
// Imagine the other dictionaries like this...
public CreateHandlers(string country)
{
return new CountrySpecificHandlers
{
Capitaliser = capitaliserDictionary[country],
PunctuationHanlder = punctuationDictionary[country],
// etc...
};
}
}
public class CountrySpecificHandlers
{
public ICapitaliser Capitaliser { get; private set; }
public IPunctuationHanlder PunctuationHanlder { get; private set; }
public ISpecialCharacterHandler SpecialCharacterHandler { get; private set; }
public ISeparatorHandler SeparatorHandler { get; private set; }
}
Что, в равной степени, я не совсем уверен, что мне нравится. Логика все еще несколько скрыта при создании фабрики, и вы не можете просто взглянуть на оригинальный метод и посмотреть, что происходит, например, при выполнении процесса «GBR». Вы также в конечном итоге создаете много классов (в более сложных примерах, чем это) в стиле GbrPunctuationHandler
, UsaPunctuationHandler
и т. Д., Что означает, что вам нужно взглянуть на несколько разных классов, чтобы выяснить все возможныедействия, которые могут произойти во время обработки знаков препинания. Очевидно, я не хочу, чтобы один гигантский класс с миллиардом if
утверждений, но в равной степени 20 классов с немного отличающейся логикой также чувствуют себя неуклюже.
В основном я думаю, что я попал в какой-то узел ООП иЯ не совсем знаю, как распутать это. Мне было интересно, был ли какой-то шаблон, который бы помог с этим типом процесса?