Supponiamo che io ho il seguente codice artificiosa:astratti metodi e il principio aperto-chiuso
abstract class Root
{
public abstract void PrintHierarchy();
}
class Level1 : Root
{
override public void PrintHierarchy()
{
Console.WriteLine("Level1 is a child of Root");
}
}
class Level2 : Level1
{
override public void PrintHierarchy()
{
Console.WriteLine("Level2 is a child of Level1");
base.PrintHierarchy();
}
}
Se sto solo guardando la classe Level2
, posso subito vedere che Level2.PrintHierarchy
segue the open/closed principle perché fa qualcosa sul suo proprio e chiama il metodo base che sta scavalcando.
Tuttavia, se guardo solo alla classe Level1
, sembra essere in violazione di OCP perché non chiama base.PrintHierarchy
- infatti, in C#, il compilatore lo vieta con l'errore "Impossibile chiamare una base astratta membro".
L'unico modo per rendere Level1
sembra seguire OCP è cambiare Root.PrintHierarchy
ad un metodo virtuale vuoto, ma poi non posso più contare sulla compilatore di applicare derivante classi per implementare PrintHierarchy
.
Il vero problema che sto avendo mantenendo il codice qui è vedere dozzine di metodi override
che non chiamano base.Whatever()
. Se base.Whatever
è astratto, allora va bene, ma in caso contrario, il metodo Whatever
potrebbe essere candidato per essere inserito in un'interfaccia invece che in un metodo di override concreto, oppure la classe o il metodo devono essere rifattorizzati in qualche altro modo, ma in entrambi i casi, indica chiaramente un design scadente.
Memorizzare che Root.PrintHierarchy
è astratto o inserire un commento all'interno di Level1.PrintHierarchy
, sono disponibili altre opzioni per identificare rapidamente se una classe formata come Level1
sta violando l'OCP?
C'è stata molta discussione nei commenti, e anche alcune buone risposte. Stavo avendo problemi a capire esattamente cosa chiedere qui. Penso che quello che mi sta frustrando è che, as @Jon Hanna points out, a volte un metodo virtuale indica semplicemente "Devi implementarmi" mentre altre volte significa "devi estendere me - se non riesci a chiamare la versione di base, rompi il mio progetto!" Ma C# non offre alcun modo per indicare quale di quelli che intendi, a parte quell'astratto o un'interfaccia chiaramente è una situazione da "implementare". (A meno che non ci sia qualcosa in Contratti di codice, che è un po 'fuori portata qui, penso).
Ma se una lingua ha avuto ha un decoratore must-attua o deve estendere, probabilmente creerebbe enormi problemi per il test dell'unità se non fosse possibile disabilitarlo. Ci sono lingue del genere? Questo suona piuttosto come design-by-contract, quindi non sarei sorpreso se fosse ad Eiffel, per esempio.
Il risultato finale è probabilmente as @Jordão says ed è completamente contestuale; ma lascerò la discussione aperta per un po 'prima di accettare ancora le risposte.
Stai cercando uno strumento di analisi statica? Se sì allora forse questo potrebbe aiutare http://stackoverflow.com/q/1627024/119477 –
@Conrad: speravo di ottenere ciò usando solo i miei occhi e il compilatore :) Ma se qualcun altro incontra questa domanda e * è * In cerca di uno strumento di analisi statica, ti consiglio vivamente di dare uno [Nitriq] (http://www.nitriq.com/) a un colpo prima di immergerti in NDepend. Ha un'edizione gratuita molto capace e anche la versione completa è abbastanza economica. –
Non penso che il metodo in 'Level1' violi (o sembri violare) l'OCP. Anche se 'Level2' non ha chiamato base, non penserei che lo stia violando. L'OCP è un principio, non un modello che dice che dovresti chiamare i membri di base sui membri sottoposti a override. –