1

単体テストの準備として、DI を使用した MVC を理解して実装するのに役立つ単純なプロジェクトを使用しています。サイトは、要求されたページに基づいて、異なるデータ テーブルを表示するだけです。問題は、データがさまざまなデータ ソース (mysql や oracle など) から取得される可能性があることです。そのため、DI を実装して、2 つを切り替えるために必要なコードを削減しようとしています。私の問題は次のとおりです。

1)データソース(mysql、oracle、または単純な古い配列)をインスタンス化し、それを必要とするオブジェクトに取得する場所(DIはこれに最適なパターンでもありますか)?

2) ソースに固有のデータクエリを配置する構造のどこに? 以下の例では、MySQL データベースにデータを照会するクラス Foo がありますが、後で Oracle データベースに移動する場合は、すべてを別の構文に書き直す必要があります。FooMysql と FooOracle の 2 つのバージョンを作成し、どちらを使用するかをどこかに指示するだけですか?

これは、私が見ている概念を示すいくつかの基本的で不完全なコードです。うまくいけば、私がこれでどこに向かっているのかを理解し、正しい方向に向けることができます. 私はすでに構築されたフレームワークを探していません。

$c = new Controller('foo');
print_r($c->getContent());

class Controller
{
    private $view = null;

    public function __construct($viewName)
    {
        $this->view = new $viewName($dbc); // where to get and pass dbc based on view
    }
}

interface ViewInterface
{
    public function getContent();
}

class FooView
{
    private $foo = null;

    public function __construct(DatabaseConnection &$dbc)
    {
        $this->foo = new Foo($dbc);
    }

    public function getContent()
    {
        return $this->foo->getAll();
    }
}

class BarView
{
    private $bar = null;

    public function __construct(DatabaseConnection &$dbc)
    {
        $this->bar = new Bar($dbc);
    }

    public function getContent()
    {
        return $this->bar->getAll();
    }
}

interface StorageInterface
{
    public function getAll();
}

class Foo implements StorageInterface
{
    private $dbc = null;

    public function __construct(DatabaseConnection &$dbc)
    {
        $this->dbc = $dbc;
    }

    public function getAll()
    {
        // mysql code to get all foos
    }
}

class Bar implements StorageInterface
{
    private $dbc = null;

    public function __construct(DatabaseConnection &$dbc)
    {
        $this->dbc = $dbc;
    }

    public function getAll()
    {
        // oracle code to get all bars
    }
}
4

1 に答える 1

1

1)データソース(mysql、oracle、または単純な古い配列の場合もあります)をインスタンス化し、それを必要とするオブジェクトに取得する場所(DIはこれに最適なパターンですか)?

DI を使用すると、コントローラーに必要な依存関係のインスタンスの作成を処理する個別の DI コンテナーが作成されます。DI は、どの DB に接続しているかを把握する必要があるフロー/制御ステートメント (if/else、switch/case) を使用する必要がなくなり、簡単な単体テストに役立つため、優れた選択肢です。DI を使用すると、これが接続先であることをオブジェクトに伝えます。

2) ソースに固有のデータクエリを配置する構造のどこに? 以下の例では、MySQL データベースにデータを照会するクラス Foo がありますが、後で Oracle データベースに移動する場合は、すべてを別の構文に書き直す必要があります。FooMysql と FooOracle の 2 つのバージョンを作成し、どちらを使用するかをどこかに指示するだけですか?

いいえ、データベース クラスのインターフェイスを作成します。そうすれば、依存関係をコントローラーに渡すときに、データベースのタイプにとらわれなくなります。

元。

public interface IDatabase {
    function connect();
    function query();
}

public class MySQLDB implements IDatabase {
    function connect() {
        // specific connection properties for mysql
    }
    function query() {
    }

}

public class PostgresDB implements IDatabase {
    function connect() {
        // specific connection properties for postgres
    }
    function query() {
    }
}

public class FooController {
    private $dataBase = null;

    public FooController(IDatabase $dataBase) {
        // guard clause
        if ($database == null)
            throw new Exception("IDatabase");

        $this->dataBase = $dataBase;
    }

    public index() {
        $this->dataBase->query();
    }
}

public class BarController {
    private $dataBase = null;

    public FooController(IDatabase $dataBase) {
        // guard clause
        if ($database == null)
            throw new Exception("IDatabase");

        $this->dataBase = $dataBase;
    }

    public index() {
        $this->dataBase->query();
    }
}

// will be hooked into your http request lifecycle
// to figure out what controller and even method is being called
// this will then return your composed controller
// we are newing up dependencies here, but they are all isolated in one location
// this way the rate of change among classes are not affecting each other
public class DIContainer {
    public resovleController() {
        // find out the http request info
        if (FooController) {
            return new FooController(new MySQLDB());
        } elseif (BarController) {
            return new FooController(new PostgresDB());
        }
    }
}

また、あなたの例にはいくつかのコードの匂いがあります。クラスの新規作成を取り除いてみてください。
また、ビューは、渡す依存関係を処理する責任を負うべきではありません。
DI コンテナーの作成と、名前空間でのコードの編成について学ぶ必要があります。
また、DI コンテナーをロードできるフロント コントローラーを作成するか、DI コンテナーをフロント コントローラーにする必要があります。

お役に立てれば。

于 2013-06-13T14:08:40.347 に答える