Qual è il design migliore per questo problema?

4

Ho un problema e voglio sapere qual è il modo migliore per risolverlo.

Problema:

Ho un albero delle decisioni binarie . Ogni nodo foglia ha un oggetto (chiamato Matrix ) che memorizza alcune informazioni ed esegue alcuni calcoli. Ad un certo punto durante l'esecuzione, voglio chiedere a Matrix se dovrei dividere il nodo foglia. Se sì, dovrei creare due bambini ognuno ha la sua matrice e dovrei eliminare la matrice del nodo corrente (perché non è più una foglia). Esistono due tipi di matrici, ma tutti i nodi foglia usano lo stesso tipo.

interface Matrix {}
class MatrixA extends Matrix {}
class MatrixB extends Matrix {}

Ho trovato diversi approcci per risolvere questo problema, ma non so quale sia il migliore.

Design # 1:

class Node {
    Node left, right;
    Matrix mat;
    MatrixFactory fact;
    Node(MatrixFactory fact) {
        this.fact = fact;
        this.mat = fact.newMatrix();
    }
    void split() {
        if (mat.isSplitNeeded()) {
            this.mat = null;
            this.left = Node(this.fact);
            this.right = Node(this.fact);
        }
    }
}

Il problema è che, mi sembra di violare Principio di responsabilità singola , perché il nodo è responsabile della struttura dell'albero, della gestione della matrice e della divisione.

Design # 2:

class Node {
    Node left, right;
}
class NodeMatrixManager {
    Map<Node, Matrix> map;
    MatrixFactory fact;
    NodeMatrixManager(MatrixFactory fact) {
        this.fact = fact;
    }
    void split(Node node) {
        mat = this.map[node];
        if (mat.isSplitNeeded()) {
            node.left = Node();
            node.right = Node();
            this.map.remove(node);
            this.map.insert(new Pair(node.left, this.fact.newMatrix()));
            this.map.insert(new Pair(node.right, this.fact.newMatrix()));
        }
    }
}

Ancora una volta ritengo di violare Principio di responsabilità singola , poiché NodeMatrixManager è responsabile sia della tracciabilità della relazione Matrix-Node, sia della suddivisione.

Design # 3:

class Node {
    Node left, right;
}
class NodeMatrixManager {
    Map<Node, Matrix> map;
    Matrix getMat(Node node) {return this.map[node];}
    insert(Node node, Matrix mat) {this.map.insert(new Pair(node, mat));}
    remove(Node node) {this.map.remove(node);}
}
class Splitter {
    NodeMatrixManager manager;
    MatrixFactory fact;
    Splitter(NodeMatrixManager manager, MatrixFactory fact) {
        this.manager = manager;
        this.fact = fact;
    }
    void split(Node node) {
        mat = this.manager.getMat(node);
        if (mat.isSplitNeeded()) {
            node.left = Node();
            node.right = Node();
            this.manager.remove(node);
            this.manager.insert(node.left, this.fact.newMatrix());
            this.manager.insert(node.right, this.fact.newMatrix());
        }
    }
}

In questo approccio sento che la classe NodeMatrixManager non è necessaria, perché ho separato Matrix dal nodo in modo che il nodo non abbia troppa responsabilità e ora Splitter ha tutte le responsabilità. Quindi, perché non rimettere semplicemente Matrix nel nodo ed evitare la mappatura non necessaria?

Design # 4:

class Node {
    Node left, right;
    Matrix mat;
    Node(Matrix mat) {this.mat = mat;}
}
class Splitter {
    MatrixFactory fact;
    Splitter(MatrixFactory fact) {
        this.fact = fact;
    }
    void split(Node node) {
        if (node.mat.isSplitNeeded()) {
            node.mat = null;
            node.left = Node(this.fact.newMatrix());
            node.right = Node(this.fact.newMatrix());
        }
    }
}

Il mio problema con questo disegno è che una classe (Splitter) sta accedendo e manipolando le informazioni memorizzate in un'altra classe (Nodo). Non sembra corretto. Se metto la divisione di nuovo in classe Node, sono tornato dove ho iniziato.

Quindi qual è il miglior approccio al design? (scusa per la lunga domanda)

    
posta Mehran 24.03.2017 - 08:20
fonte

1 risposta

9

La maggior parte delle tue scelte progettuali sembra essere incentrata sul Principio della singola responsabilità. Prenderò più facilmente la tua decisione di progettazione chiarendo questo principio.

La Single Responsibility non significa "fare solo una cosa". Significa "avere un solo motivo per cambiare", che è un po 'ottuso. Ecco cosa significa.

Supponiamo che tu abbia un lavoratore che è il capoturno in un ristorante fast-food locale. Quante responsabilità ha? Più di uno, dici? Come potrebbe essere? Il suo lavoro è il suo lavoro, non a causa della lista di responsabilità che ha, ma perché il suo titolo di lavoro comprende effettivamente quelle responsabilità.

Assumerai più persone perché il responsabile del turno ha più di una responsabilità? No, non lo faresti; ti aspetteresti che soddisfi tutte le sue responsabilità lavorative. Vuoi assumere più persone perché ha troppe responsabilità? Possibilmente. Ma l'unico modo in cui cambieranno le sue responsabilità fondamentali è se cambia la sua mansione. Il gestore del turno non capovolge gli hamburger, perché è il lavoro di qualcun altro

Se un lavoratore dovrebbe avere una sola ragione per cambiare (cioè il suo titolo di lavoro), come lo cambia? Cambia i lavori.

Quindi che tipo di ristorante abbiamo qui? Un ristorante Albero delle decisioni binarie . Di quanti lavoratori hai bisogno? Che titoli di lavoro avranno?

Un'altra cosa. Il ristorante non sarà religioso su quei titoli di lavoro. Se il gestore ha bisogno di spazzare il pavimento, spazza il pavimento.

Buona fortuna.

    
risposta data 24.03.2017 - 16:38
fonte

Leggi altre domande sui tag