Щось у моїй роботі зараз виникає досить багато, - це те, що існує узагальнений процес, який має відбутися, але тоді непарна частина цього процесу повинна відбуватися дещо інакше залежно від значення певної змінної, і я не цілком впевнений, який найелегантніший спосіб впоратися з цим.
Я буду використовувати приклад, який у нас зазвичай є, який робить дещо інакше залежно від країни, з якою ми маємо справу.
Тож у мене клас, назвемо його 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 класів зі злегка різною логікою також почуваються незграбними.
В основному я думаю, що я потрапив у якийсь вузол OOP і не зовсім знаю хорошого способу розплутати його. Мені було цікаво, чи існує там схема, яка допомогла б цьому процесу?
if (country == "DEU")
вас перевіряють if (config.ShouldRemovePunctuation)
.
country
PreProcess
функціонал, який можна було б реалізувати по-різному залежно від деяких країн,DetermineSeparator
може бути там для всіх, і aPostProcess
. Усі вони можуть бутиprotected virtual void
з типовою реалізацією, і тоді ви можете мати конкретнуProcessors
країну