Quelque chose qui revient beaucoup dans mon travail actuel est qu'il y a un processus généralisé qui doit se produire, mais ensuite la partie étrange de ce processus doit se produire légèrement différemment selon la valeur d'une certaine variable, et je ne suis pas Je suis sûr que c'est la façon la plus élégante de gérer cela.
Je vais utiliser l'exemple que nous avons habituellement, qui fait les choses légèrement différemment selon le pays avec lequel nous traitons.
J'ai donc une classe, appelons-la 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);
}
}
Sauf que seules certaines de ces actions doivent se produire pour certains pays. Par exemple, seuls 6 pays nécessitent l'étape de capitalisation. Le personnage sur lequel diviser peut changer selon le pays. Le remplacement de l'accentuation 'e'
peut uniquement être requis en fonction du pays.
Évidemment, vous pouvez le résoudre en faisant quelque chose comme ceci:
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);
}
Mais lorsque vous traitez avec tous les pays possibles dans le monde, cela devient très lourd. Et peu importe, les if
instructions rendent la logique plus difficile à lire (du moins, si vous imaginez une méthode plus complexe que l'exemple), et la complexité cyclomatique commence à monter assez rapidement.
Donc en ce moment je fais en quelque sorte quelque chose comme ça:
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);
}
}
Gestionnaires:
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; }
}
Et je ne suis pas vraiment sûr d’aimer. La logique est encore quelque peu obscurcie par toute la création d'usine et vous ne pouvez pas simplement regarder la méthode d'origine et voir ce qui se passe lorsqu'un processus "GBR" est exécuté, par exemple. Vous finissez également par créer beaucoup de classes (dans des exemples plus complexes que celui-ci) dans le style GbrPunctuationHandler
, UsaPunctuationHandler
etc ... ce qui signifie que vous devez regarder plusieurs classes différentes pour comprendre toutes les actions possibles qui pourraient se produire pendant la ponctuation manipulation. Évidemment, je ne veux pas d'une classe géante avec un milliard d' if
instructions, mais 20 classes avec une logique légèrement différente me semblent également maladroites.
Fondamentalement, je pense que je me suis retrouvé dans une sorte de nœud OOP et je ne sais pas très bien comment le démêler. Je me demandais s'il y avait un modèle qui pourrait aider avec ce type de processus?
if (country == "DEU")
vous vérifier if (config.ShouldRemovePunctuation)
.
country
une chaîne plutôt qu'une instance d'une classe qui modélise ces options?
PreProcess
fonctionnalité, qui pourraient être mises en œuvre différemment selon certains pays,DetermineSeparator
peuvent être là pour tous, et unPostProcess
. Tous peuvent êtreprotected virtual void
avec une implémentation par défaut, et vous pouvez alors avoir unProcessors
pays spécifique