Miglior modello di progettazione per libreria con modello di dati

2

Sto refactoring una vecchia libreria Codeigniter per essere indipendente dal framework php. Ci sono queste parti principali:

  • l'oggetto di connessione - questo verrà da "utente"; cioè, la connessione del framework o la propria libreria di connessione. La mia libreria non vorrà "saperlo" tranne che (inizialmente) sarà un oggetto conn PDO (ma le cose dovrebbero essere scritte per gestire un tipo di driver nativo)

  • l'oggetto modello - esegue le query e amp; restituisce matrice di risultati (o array di errori) alla lib principale. Come è ora, è molto "sottile" e ha solo transazioni, creazione di query e amp; la query db attuale

  • l'interfaccia del modello - Sono un grande fan delle interfacce e vedo questo modello come scambiabile per un modello NoSQL, ad esempio

  • la libreria principale - nella mia attuale libreria CI, questo 1) riceve la richiesta di funzione, 2) convalida i parametri passati ad esso, 3) richieste dal modello, 4) crea un array di risposta che include i dati & codici di errore e messaggi (configurabile in più lingue, ma in realtà non fa parte di questa domanda)

Quindi, in sintesi, il modo in cui funziona ORA si trova nel controller o nella pagina chiamante:

1) chiama la funzione di lib principale 2) modello principale di chiamate lib 3) il modello ritorna alla libreria principale 4) ritorni della lib principale al controller

ORA inizia la mia domanda sul modello di design reale:

Vorrei passare il mio oggetto conn via DI alla mia libreria principale, ma mi piacerebbe anche passare il mio modello tramite DI alla libreria principale per mantenere le cose flessibili. L'obiettivo di flessibilità che sto cercando sarebbe quello di consentire alle persone di creare i propri modelli Native DB o NoSQL & passare connessioni non PDO in questo, quindi tenerle disaccoppiate sembra ottimale.

MA per fare questo, l'unica cosa che posso pensare sarebbe come:

(controller - dove potrei effettivamente eseguire la query nella lib, non nel modello)

$conn //from the user
$model = new MyModel();
$lib = new MyLib($conn, $model);

o

$conn //from the user
$model = new MyModel($conn);
$lib = new MyLib($model);

che sembra più "naturale" dal momento che la query & conn tendono a lavorare insieme

In entrambi i casi l'utente è piuttosto maldestro e non posso fare a meno di chiedermi se non stia esagerando con questa intera cosa di DI o se abbia scelto il modello di progettazione sbagliato per farlo.

Sarebbe molto gradito qualsiasi consiglio su come impostarlo al meglio - ho passato più tempo a pensare a questo che mi ci vorrà per rifattorizzare il codice reale!

TIA

    
posta jmadsen 16.03.2014 - 09:53
fonte

2 risposte

3

Potrei essere waaaaaay spento, ma ...

Sembra che il modello a sia necessario per usare la libreria, semplicemente non ti interessa quale, giusto? Inoltre, la libreria non si cura di come il modello ottiene i suoi dati, o da dove provengono i dati, vuole solo un oggetto che soddisfi i criteri dell'interfaccia.

Se la libreria non ha bisogno dell'oggetto di connessione, allora sii responsabile del modello.

interface MyFooModelInterface 
{
    public function getItem($id);
    public function addItem($item);
    ...
}

Ed ecco un semplice esempio di classe:

class MyLib
{
    protected $model;

    public function __construct(MyFooModelInterface $model)
    {
        $this->model = $model;
    }

    public function getItemById($id)
    {
        return $this->model->getItem($id);
    }
}

E un esempio di modello:

class MyModel implements MyFooModelInterface
{
    protected $conn;

    public function __construct(\PDO $conn)
    {
         $this->conn = $conn;
    }

    public function getItem($id)
    {
        ...
    }
    public function addItem($item)
    {
        ...
    }
}

Ed ecco un esempio di utilizzo:

// the model is responsible for handling the data retrieval, not the library
$model = new Model($conn);

$lib = new MyLib($model);
return $lib->getItem($id);

Ora, se decido che voglio una soluzione basata su file, posso facilmente scambiare il modello. Per testare il modello, viene iniettata la connessione obj, quindi è facile. Per testare la libreria, il modello viene anche iniettato, quindi, di nuovo, è facile.

In questo caso, il modello è responsabile solo per ottenere i dati, mentre la biblioteca è responsabile della gestione e dell'elaborazione dei dati. Niente importa cosa o come fa l'altro.

Modifica

la libreria con un metodo factory per creare il modello se non ne è stato dato nessuno ...

class MyLib
{
    protected $model;

    public function __construct(MyFooModelInterface $model = null, $conn = null)
    {
        // if we have a model, use it
        if (!is_null($model)) { 
            $this->model = $model; 
        }

        // if we don't have a model, but have a connection obj, make a model
        if (is_null($model) && !is_null($conn)) { 
            $this->model = $this->factoryModel($conn); 
        }

        // if we don't have either, quit and go home
        if (is_null($model) && is_null($conn)) {
            throw new Exception('need moar inputs');
        }
    }

    protected factoryModel($conn)
    {
        $this->model = new MyModel($conn);
    }

    public function getItemById($id)
    {
        return $this->model->getItem($id);
    }
}
    
risposta data 17.03.2014 - 23:59
fonte
0

Potrebbe non essere il "più pulito", ma come aggiungere una funzione per sovraccaricare il modello. Quindi, per impostazione predefinita, la libreria può creare un'istanza del modello in modo che sia completamente pulita per l'utente, ma durante i test è possibile sovraccaricarla.

Non sono un test difficile da morire, quindi questa risposta potrebbe essere facilmente confutata.

    
risposta data 16.03.2014 - 10:18
fonte

Leggi altre domande sui tag