Qualcosa che emerge molto nel mio lavoro attuale è che c'è un processo generalizzato che deve accadere, ma poi la parte strana di quel processo deve avvenire in modo leggermente diverso a seconda del valore di una certa variabile, e non lo sono abbastanza sicuro qual è il modo più elegante per gestirlo.
Userò l'esempio che di solito abbiamo, che sta facendo le cose in modo leggermente diverso a seconda del paese con cui abbiamo a che fare.
Quindi ho una lezione, chiamiamola 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);
}
}
Solo che alcune di queste azioni devono avvenire per alcuni paesi. Ad esempio, solo 6 paesi richiedono il passaggio di capitalizzazione. Il personaggio su cui dividere potrebbe cambiare in base al Paese. La sostituzione dell'accento 'e'
potrebbe essere richiesta solo in base al Paese.
Ovviamente potresti risolverlo facendo qualcosa del genere:
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);
}
Ma quando hai a che fare con tutti i possibili paesi del mondo, diventa molto ingombrante. E a prescindere, le if
dichiarazioni rendono la logica più difficile da leggere (almeno, se immagini un metodo più complesso dell'esempio), e la complessità ciclomatica inizia a insinuarsi piuttosto velocemente.
Quindi al momento sto facendo qualcosa del genere:
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);
}
}
gestori:
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; }
}
Che ugualmente non sono davvero sicuro che mi piaccia. La logica è ancora un po 'oscurata da tutta la creazione della fabbrica e non puoi semplicemente guardare il metodo originale e vedere cosa succede quando viene eseguito un processo "GBR", per esempio. Finisci anche per creare molte classi (in esempi più complessi di questo) nello stile GbrPunctuationHandler
, UsaPunctuationHandler
ecc ... il che significa che devi guardare diverse classi per capire tutte le possibili azioni che potrebbero accadere durante la punteggiatura la manipolazione. Ovviamente non voglio una classe gigante con un miliardo di if
affermazioni, ma ugualmente 20 classi con una logica leggermente diversa mi sembrano goffe.
Fondamentalmente penso di essermi preso una specie di nodo OOP e non conosco bene un modo per districarlo. Mi chiedevo se ci fosse uno schema là fuori che potesse aiutare con questo tipo di processo?
if (country == "DEU")
controllare if (config.ShouldRemovePunctuation)
.
country
una stringa anziché un'istanza di una classe che modella queste opzioni?
PreProcess
funzionalità, che potrebbe essere implementata in modo diverso in base ad alcuni dei paesi,DetermineSeparator
può essere lì per tutti loro, e aPostProcess
. Tutti possono essereprotected virtual void
con un'implementazione predefinita e quindi puoi avere specificiProcessors
per paese