Ci sono grossi problemi con la complessità nell'esempio sopra:
- La struttura effettiva del problema è l'array 2d (di booleani) in cui una dimensione è riquadri e un'altra dimensione è le proprietà. Questa struttura proviene praticamente da Visual Basic dal 1980.
- Poi ci sono espressioni boolearie arbitrarie che manipolano questi booleani dall'array 2d
Queste due caratteristiche insieme lo rendono estremamente complesso. Ad esempio, il test del funzionamento del codice richiede l'attraversamento di tutti gli elementi dell'array 2d (e la valutazione dell'espressione booleana in ogni elemento dell'array 2d) e quindi un'ulteriore valutazione delle espressioni booleane che collegano le righe e le colonne dell'array 2d. È come aggiungere il foglio di calcolo Excel al tuo programma e poi farlo calcolare alcuni valori dai dati; salvo che è necessario aggiungere manualmente i setter / getter e manipolare i dati è molto oneroso. La complessità è ancora lì.
Quindi la mia raccomandazione è di cercare di renderlo più semplice in qualche modo - ridurre righe / colonne è un inizio, ma cerca di eliminare la struttura di array 2d. In modo che non è necessario implementare l'intero excel per questo. Excel utilizza anche questo tipo di array 2d in cui ogni nodo può contenere dati tipizzati in modo diverso. Queste convenzioni provenienti da C # sembrano avere questo tipo di complessità nascosta in esse.
Ecco un codice c ++ che è praticamente equivalente al tuo codice sopra e ti permette di vedere la struttura attuale dell'array 2d:
template<class T> class Array1d { virtual T Map(int x) const=0; };
class Array2d { virtual bool Map(int x, int y) const=0; };
class Array2dImpl : public Array2d {
Array2dImpl(Array1d<Box> &b) : b(b) { }
bool Map(int x, int y) const
{ if (y==0) { return b.Map(x).width < maxwidth; }
if (y==1) { return b.Map(x).height < maxheight; }
... }
Array1d<Box> &b;
int maxwidth;
int maxheight;
};
class BooleanExpression : public Array1d<bool>
{
public:
BooleanExpression(Array2d &a) : a(a) { }
bool Map(int x) const { return a.Map(x,0) && a.Map(x,1) && a.Map(x,2) && a.Map(x,3); }
private:
Array2d &a;
};
Come il tuo esempio sopra, questo codice può essere usato con una semplice porzione di codice:
int main() {
Array1d<Box> boxes;
Array2dImpl array(boxes);
BooleanExpression e(array);
for(int i=0;i<e.size();i++)
{
if (e.Map(i)) { /* do something */ }
}
}
Ora torniamo alla tua domanda su come impostare la variabile maxwidth in questo esempio. Potrebbe sembrare che richieda setter separato per ogni proprietà. Ma non è questo il caso, in realtà, il modo migliore è aggiungere una funzione come questa:
void SetElement(int x, int y, bool b);
Questo appartiene naturalmente all'array 2d che è già incluso nel tuo esempio. Il vero problema con questo esempio è che ci sono 2 ^ (x * y) diversi stati in cui può essere inserito il sistema. Questo deriva da x * y chiamate a SetElement. Questo tipo di esplosione dello stato è completamente pazzesco per un sistema del genere e questo potrebbe infrangere il tuo software molto male.
Anche se assumiamo che tu voglia generare x * y booleani usando il codice sopra fornendo semplicemente le dimensioni, il trucco di come il tuo esempio ha fatto la malvagia complessità è molto nascosto. Passare la confezione dalla funzione foreach a PassesFilter () sembra molto semplice, ma causa tutto questo problema, riconfigurando tutti i booleani nella singola riga dell'eccel. Correlato è anche lo spazio di stato coinvolto nelle coordinate delle caselle. Questi sono anche problemi peggiori.
(e no, nascondere l'array 2d usando il codice C # non lo rende più facile da capire,)
(In realtà, è molto malvagio pubblicare questo codice per gli altri programmatori da leggere, spero tu non sappia che l'array 2d è lì e hai ancora la possibilità di riparare in qualche modo il tuo software ...)