Ho scritto un sistema che calcola gli sconti per un carrello della spesa basato su un insieme di regole. Ogni regola è implementata con la seguente interfaccia (C #):
interface IRule
{
bool IsActive();
bool IsApplicableTo(IShoppingCart cart);
decimal CalculateDiscount(IShoppingCart cart);
}
Un'implementazione concreta potrebbe essere simile a questa:
class Rule : IRule
{
bool IsActive() { return true; }
bool IsApplicableTo(IShoppingCart cart)
{
if (!IsActive())
return false;
return TestIfApplicable(cart);
}
decimal CalculateDiscount(IShoppingCart cart)
{
if (!IsApplicableTo(cart))
return 0m;
return CalculateStuff(cart);
}
}
Ora sto cercando di introdurre alcune registrazioni nel sistema. Per mantenere le cose pulite, non voglio inserirle nella classe Rule. Così ho pensato di creare un decoratore per IRule, che gestisce la registrazione:
class LoggingRule : IRule
{
IRule decoratedRule;
bool IsActive()
{
LogImportantThings();
return decoratedRule.IsActive();
}
//And so on.
}
Il problema che sto incontrando qui, è che la classe Rule chiama in realtà i metodi IsActive e IsApplicableTo. Quando ciò accade, il decoratore viene semplicemente passato e non viene registrato nulla.
Suppongo che potrei rendere la LoggingRule una sottoclasse di Rule. Significherebbe che dovrei fare una variante LoggingRule per ogni implementazione IRule. Ciò potrebbe potenzialmente causare molte duplicazioni.
Potrei anche inserire la registrazione in una classe base e usare il modello di oggetto Null quando non voglio registrare nulla. Ma poi di nuovo, 99 su 100 volte non voglio registrare nulla. E quando questi metodi vengono chiamati molte volte, vale la pena di un potenziale sovraccarico?
Quindi nessuna delle due soluzioni sembra particolarmente elegante, e sto lottando per trovare un'alternativa migliore ... Qualche suggerimento?