A volte mi trovo a scrivere commenti su metodi di classe come questo:
class A : public Base
{
public:
/**
* Sets variable;
* should be called before ImplementsInterfaceMtehod(),
* else has no effect.
*/
void SetSomeVariable( var_type value );
virtual void ImplementsInterfaceMethod();
}
I chiamanti di Base::ImplementsInterfaceMethod
ovviamente non conoscono la variabile e non dovrebbero. Ma gli utenti di A
dovrebbero impostare la variabile se vogliono che diventi effettiva. Non è necessario impostare la variabile (altrimenti potrebbe essere un parametro per il costruttore), quindi non posso lanciare eccezioni in ImplementsInterfaceMethod
se non è impostato.
Questo è un segno di alcune tipiche cattive pratiche? C'è un modo migliore di scrivere un commento come mostrato per affrontare questo?
modifica ecco un esempio più concreto simile alla parte di un codice di elaborazione di immagini 3D in tempo reale; a causa della parte in tempo reale e il fatto che le immagini possono diventare enormi, tutto deve essere preallocato.
class DataProcessor
{
public:
/**
* Sets dimensions of the data for the next call to Process().
* Can be used by implementations to setup internals, eg preallocate.
* Upon returning out contains the dimensions that will be returned
* by the Process call, given dims as input dimensions.
* (A)
*/
virtual bool SetInputDimensions( const Dimensions& dims, Dimensions& out ) = 0;
virtual bool Process( const Data& in, Data& out ) = 0;
};
class ImageStitcher : public DataProcessor
{
/**
* Set size of the output image returned by Process() as a factor,
* eg when size == 2, image will be twice as big.
* (B)
*/
void SetOutputSize( const double size );
/**
* Set the position at which the next Data object passed to Process()
* will be stitched.
* (C)
*/
void SetStitchPosition( double x, double y, double alpha );
}
Quindi qui (A) deve essere chiamato almeno una volta prima che Process () venga chiamato. Che impongo restituendo un errore in Process (), se così non fosse. La maggior parte delle volte le dimensioni non sono note quando si costruisce l'oggetto, anche se un parametro costruttore non è un'opzione. Due componenti principali utilizzano l'interfaccia DataProcessor: tutti i processori si trovano in una rete di processori e tale rete non è a conoscenza del tipo di processore, si occupa solo del trasferimento dei dati tra di loro chiamando Process () più volte. Un altro componente si occupa della configurazione della rete chiamando SetInputDimensions (), ancora una volta inconsapevole del tipo di processore.
(B) dovrebbe essere chiamato prima che SetInputDimensions () venga chiamato, in quanto definisce la dimensione dell'immagine risultante.
(C) dovrebbe essere chiamato prima di ogni chiamata per elaborare altrimenti la stitcher non sa dove mettere l'immagine
Ora questa intera rete di elaborazione viene effettivamente utilizzata in applicazioni commerciali e funziona molto bene poiché ho fatto in modo che tutto venga chiamato in ordine. Eppure ogni volta che scrivo "deve / deve essere chiamato prima" le campane iniziano a suonare dappertutto ..