2

私は現在、サードパーティの開発者に使用してもらいたい API の構築を支援しています。この API は、クラウド内のサービスにフックします。このサービスは常に変化しており、現時点ではあまり信頼できません。したがって、SDK で実際のクライアントと偽のクライアントの両方を提供したいと考えています。サービスがダウンしたときはいつでも、開発者は本物のクライアントではなく偽のクライアントを使用して、コーディングを続けることができます。

私はあらゆる種類のデザインパターンを調べましたが、いくつかは私の問題にうまく対処しました。ただし、問題は次のとおりです。コードをできるだけ単純にしたいと考えています。たとえば、私のサービスが Experia と呼ばれているとします。私は人々がこのようなことをできるようにしたい:

class Experia extends Exp

...

$ex = new Experia(/*initialization parameters*/);  //init prameters like user name, password etc
$ex->story()->create($storyArgs);

現在、Experia は、これらのリソースとそれらが利用できるファイルのリストを含む別のクラス Exp を拡張するクラスです。また、基本的な get() および post() メソッドなどを定義する Client と呼ばれるジェネリック クラスも拡張します。そして基本的にクライアントのリモートURLなどを設定します(ペストライブラリをラップします)

したがって、Exp は次のようになります。

class Exp extends Client
{     
    public function story() {
         include_once('classes/User.php');
    }

    //other resource methods

}

すべての偽のリソースを含む別のクラスを作成したい..次のようなもの:

class ExpFake extends Client
{     
    public function story() {
         include_once('classesFake/User.php');
    }

    //other resource methods

}

これが私が直面している問題です。私は Experia がその宣言に応じて Exp または ExpFake を醜いことなく拡張できることを望んでいます..そして醜いとは、私の API を使用する開発者が使用しなければならない余分なコードを意味します。たとえば、私がやろうとしたことの1つは、クライアントをExpから切り離し、基本的にこれを行うことでした

$ex = new Experia(/*... */);
$ex->client = new fakeClient();   //I could also do $ex-> client = new realClient();

しかし、問題は、使用したいたびにリソースを呼び出すことでした..クライアントを指定する必要がありました:

$this->client->story()->create($args)

クライアント部分は、API に含めることができない余分なコードです。

簡単に言えば..あるクラスまたは別のクラスから選択的に継承するのと同じ結果を達成するデザインパターン(または可能であれば直接的な方法..php)は何ですか

これを行うオプションがあるように:

class Experia extends (Experia の初期化パラメータに応じて Exp または ExpFake のいずれか)

4

2 に答える 2

2

良い方法は、アダプター パターンです。主なクライアントはExpクラスであり、開発者がサービスと対話するために使用します。ただし、このクラスは、サービスに接続するアダプターに依存します。このアダプター クラスは、インスタンス化時に注入する必要がありExp、必要に応じてモックできる部分です。

class Exp {

    protected $adapter;

    public function __construct(ExpAdapter $adapter) {
        $this->adapter = $adapter;
    }

    public function foo() {
        return $this->adapter->doFoo();
    }

}

abstract class ExpAdapter {

    abstract public function doFoo();

}

次に、実際ExpAdapterのモックとモックを作成できます。

class LiveExpAdapter extends ExpAdapter {

    public function doFoo() {
        // contact the actual service
    }

}

class MockExpAdapter extends ExpAdapter {

    public function doFoo() {
        return true;
    }

}

abstractクラスを拡張する代わりに、interface仕様を使用することもできます。

開発者にとって、これは次のようになります。

$exp = new Exp(new LiveExpAdapter);
// if service is down, use instead:
// $exp = new Exp(new MockExpAdapter);

$exp->foo();
于 2012-06-04T10:00:31.533 に答える
0

PHPのバージョンにもよりますが、その場合は特性を使用します

trait Exp {

}
trait ExpFake {

}    
class Experia {
    use Exp;
}

ドライバーを使用した代替も問題ありません。たとえば、インターフェイスを定義し、ドライバーまたは実装を個別に定義します(dbと同様に、mysql、psqlなどの異なるドライバークラスがある場合)

于 2012-06-04T10:06:17.053 に答える