PHP/Laravel API class 实现的接口
PHP/Laravel Interface for API class realization
我有一个带有搜索功能的界面:
interface Searcher
{
public function search($text,$limit)
}
我有一些实现是基于API
class APISeach implements Searcher
{
public function search($text,$limit)
{
$params = [
'name' => $sName,
'maxRows' => $iLimit,
];
$response = Http::get('http://some_api_service/search', $params)->json();
}
}
我有一些使用此搜索的代码:
class MyController extends Controller
{
private $seacher;
public function __construct(Searcher $mySeacher)
{
$this->seacher = $mySeacher;
}
public function search($text,$limit=10)
{
$this->seacher->search($text,$limit)
}
}
一切看起来都很好(可能是)。但是,如果我需要更改 API 实现并且需要另一个参数怎么办。例如:
class AnotherAPISeach implements Searcher
{
public function search($text,$language,$fuzzy,$limit)
{
$ApiObjectFromLib = new ApiObjectFromLib();
$response = $ApiObjectFromLib->search($text,$language,$fuzzy,$limit)->json();
}
}
所以它不能再实现 Searcher 接口了。
是否存在使用 API 函数接口的任何方式?所有 API 都可能需要各种参数,如果我需要为每个 API 更改接口或控制器代码,那就不好了。
您可以使用variadic arguments
interface Searcher
{
public function search($text, $limit, ...$additional);
}
如果这违背了 interface
的目的,则由您决定
这样的事情怎么样 (demo)?
public function search(string $name, int $limit = \Search\Limit::DEFAULT)
{
return $this->api->search(
new \Search\Name($name),
new \Search\Limit($limit)
);
}
public function lookup(
string $name,
string $language = \Search\Language::DEFAULT,
bool $fuzzy = \Search\Fuzzy::DEFAULT,
int $limit = \Search\Limit::DEFAULT
) {
return $this->api->search(
new \Search\Name($name),
new \Search\Language($language),
new \Search\Fuzzy($fuzzy),
new \Search\Limit($limit)
);
}
这些“规范”看起来像这样:
namespace Search
{
interface Specification
{
public function __invoke(array $params): array;
}
class Name implements Specification
{
private $name = null;
public function __construct(string $name)
{
$this->name = $name;
}
public function __invoke(array $params): array
{
return [
'name' => $this->name,
];
}
}
class Language implements Specification
{
const DEFAULT = 'en';
private $language = null;
public function __construct(string $language)
{
$this->language = $language;
}
public function __invoke(array $params): array
{
return [
'language' => $this->language ?? 'en',
];
}
}
class Fuzzy implements Specification
{
const DEFAULT = true;
private $fuzzy = null;
public function __construct(bool $fuzzy)
{
$this->fuzzy = $fuzzy;
}
public function __invoke(array $params): array
{
return [
'fuzzy' => $this->fuzzy,
];
}
}
class Limit implements Specification
{
const DEFAULT = 10;
private $max = null;
public function __construct(int $limit)
{
$this->limit = $limit;
}
public function __invoke(array $params): array
{
return [
'maxRows' => $this->limit ?: self::DEFAULT,
];
}
}
}
可搜索的API是这样组成的:
interface Searchable
{
public function search(\Search\Specification... $criteria);
}
class Search implements Searchable
{
private $url = '/search';
private $defaults = [
'maxRows' => \Search\Limit::DEFAULT,
];
public function search(\Search\Specification ...$criteria)
{
return \Http::get($this->url, array_reduce(
$criteria,
fn($params, $criteria) => $criteria($params) + $params,
$this->defaults
))->json();
}
}
Specification Pattern 很有趣,因为它暗示对域的请求实际上只是一系列决策,这些决策会导致可在其他地方应用的配置。
例如,请注意上面的 $criteria($params)
个对象是如何为每个请求提供当前 $params
的,它可能会覆盖参数、读取和修改参数,或者可能包含一个规范检查以验证参数。
关于 array + array
语法的注意事项,这是一种合并数组的方法:
['foo' => 'bar'] + ['foo' => 'baz'] // left takes precedence: ['foo' => 'bar']
Filter/Criteria 非常相似;我倾向于认为那些对其应用的对象(存储库、查询或集合)比规范更严格 link,在我看来,规范更适用于要返回的内容。
我有一个带有搜索功能的界面:
interface Searcher
{
public function search($text,$limit)
}
我有一些实现是基于API
class APISeach implements Searcher
{
public function search($text,$limit)
{
$params = [
'name' => $sName,
'maxRows' => $iLimit,
];
$response = Http::get('http://some_api_service/search', $params)->json();
}
}
我有一些使用此搜索的代码:
class MyController extends Controller
{
private $seacher;
public function __construct(Searcher $mySeacher)
{
$this->seacher = $mySeacher;
}
public function search($text,$limit=10)
{
$this->seacher->search($text,$limit)
}
}
一切看起来都很好(可能是)。但是,如果我需要更改 API 实现并且需要另一个参数怎么办。例如:
class AnotherAPISeach implements Searcher
{
public function search($text,$language,$fuzzy,$limit)
{
$ApiObjectFromLib = new ApiObjectFromLib();
$response = $ApiObjectFromLib->search($text,$language,$fuzzy,$limit)->json();
}
}
所以它不能再实现 Searcher 接口了。 是否存在使用 API 函数接口的任何方式?所有 API 都可能需要各种参数,如果我需要为每个 API 更改接口或控制器代码,那就不好了。
您可以使用variadic arguments
interface Searcher
{
public function search($text, $limit, ...$additional);
}
如果这违背了 interface
的目的,则由您决定
这样的事情怎么样 (demo)?
public function search(string $name, int $limit = \Search\Limit::DEFAULT)
{
return $this->api->search(
new \Search\Name($name),
new \Search\Limit($limit)
);
}
public function lookup(
string $name,
string $language = \Search\Language::DEFAULT,
bool $fuzzy = \Search\Fuzzy::DEFAULT,
int $limit = \Search\Limit::DEFAULT
) {
return $this->api->search(
new \Search\Name($name),
new \Search\Language($language),
new \Search\Fuzzy($fuzzy),
new \Search\Limit($limit)
);
}
这些“规范”看起来像这样:
namespace Search
{
interface Specification
{
public function __invoke(array $params): array;
}
class Name implements Specification
{
private $name = null;
public function __construct(string $name)
{
$this->name = $name;
}
public function __invoke(array $params): array
{
return [
'name' => $this->name,
];
}
}
class Language implements Specification
{
const DEFAULT = 'en';
private $language = null;
public function __construct(string $language)
{
$this->language = $language;
}
public function __invoke(array $params): array
{
return [
'language' => $this->language ?? 'en',
];
}
}
class Fuzzy implements Specification
{
const DEFAULT = true;
private $fuzzy = null;
public function __construct(bool $fuzzy)
{
$this->fuzzy = $fuzzy;
}
public function __invoke(array $params): array
{
return [
'fuzzy' => $this->fuzzy,
];
}
}
class Limit implements Specification
{
const DEFAULT = 10;
private $max = null;
public function __construct(int $limit)
{
$this->limit = $limit;
}
public function __invoke(array $params): array
{
return [
'maxRows' => $this->limit ?: self::DEFAULT,
];
}
}
}
可搜索的API是这样组成的:
interface Searchable
{
public function search(\Search\Specification... $criteria);
}
class Search implements Searchable
{
private $url = '/search';
private $defaults = [
'maxRows' => \Search\Limit::DEFAULT,
];
public function search(\Search\Specification ...$criteria)
{
return \Http::get($this->url, array_reduce(
$criteria,
fn($params, $criteria) => $criteria($params) + $params,
$this->defaults
))->json();
}
}
Specification Pattern 很有趣,因为它暗示对域的请求实际上只是一系列决策,这些决策会导致可在其他地方应用的配置。
例如,请注意上面的 $criteria($params)
个对象是如何为每个请求提供当前 $params
的,它可能会覆盖参数、读取和修改参数,或者可能包含一个规范检查以验证参数。
关于 array + array
语法的注意事项,这是一种合并数组的方法:
['foo' => 'bar'] + ['foo' => 'baz'] // left takes precedence: ['foo' => 'bar']
Filter/Criteria 非常相似;我倾向于认为那些对其应用的对象(存储库、查询或集合)比规范更严格 link,在我看来,规范更适用于要返回的内容。