2

我目前正在帮助构建一个我希望 3rd 方开发人员使用的 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 的类,其中包含这些资源的列表以及它们可用的文件。它还扩展了一个名为 Client 的通用类,它定义了基本的 get() 和 post() 方法等,并且基本上设置了客户端远程 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 的开发人员必须使用的任何额外代码。因此,例如,我尝试做的一件事是将客户端与 Exp 分离,并且基本上这样做

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

但问题是每次我想使用调用资源时..我必须指定客户端:

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

客户端部分是我无法包含在我的 api 中的额外代码。

长话短说..什么是设计模式(或直接方式,如果可能的话..在php中)与选择性地从一个类或另一个类继承相同的结果是什么

就像可以选择这样做:

Experia 类扩展(Exp 或 ExpFake 取决于 Experia 的初始化参数)

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 回答