面向对象编程语言的Formal semantics包括封装状态。在状态更改之前是否有用于封装潜在变更的用例?虽然以下示例是PHP格式的,但您也应该在答案中认为与语言无关。
我有一个Client
对象,其职责是发送请求并从服务器检索响应,这用于通过调用API来更改驻留在另一台服务器上的对象的状态。有几个Url,一个具有端点create
,另一个具有端点update
。问题是,update
可用于更新给定对象中的多个不同元素,每个元素都需要不同的参数。
想象一下object
拥有以下对象:
要更改ImageLayer
,API需要:
要更改TextLayer
,API需要:
现在在您认为可以简单地将其抽象为id和替换值之前,请考虑AudioLayer
:
我最初考虑添加Client::updateImageLayer()
,Client::updateTextLayer()
,但后来意识到Client
对象在将来{@ 1}}时可能会呈指数级变大。
然后我考虑添加(N)Layer
,但我认为这不够好。
最后,这是我一直在考虑的另一个选项: Client::updateLayer(Layer $layer, array $values)
对象。
如果我创建了一个Change
对象,将更改封装到任何特定图层,然后将其传递给已经验证的Change
,并准备好在请求中发送,该怎么办? API?
Client
使用上面的内容,interface Change
{
public function isValid();
public function getChanges();
}
class ImageLayerChange implements Change
{
protected $url;
protected $id;
public function __construct($id, $url)
{
$this->url = $url;
$this->id = $id;
}
public function isValid()
{
// Use a validator object to check url is valid etc
}
public function getChanges()
{
return array($this->id, $this->url);
}
}
对象可以围绕一组Client
个对象循环,我甚至可以创建一个Change
,通过调用{{1}确保它们全部有效}},并调用ChangeSet
将特定数组直接发送到API,因为它已经过全部验证。
我之前从未听说过建模更改。您对上述选项有何看法?我是不是太复杂了?我喜欢能够随意添加/删除isValid()
更改的想法,以及所有内容仍能正常工作,因为它们符合getChanges()
界面。
也许我不是最好的方式吗?我的解决方案有什么不好吗?
在使用我的解决方案或您建议的解决方案时,我使用或应该考虑的模式是什么?我对好的代码感兴趣。
答案 0 :(得分:1)
根据您的描述,在我看来,您需要一个API客户端和请求对象。
namespace Api;
interface Client {
/**
* @param string $method
* @param string $urn
* @param array $params
* @return Response
*/
public function call($method, $urn, array $params = array());
}
interface Request {
public function isValid();
public function make(Client $client);
}
例如实现类似的东西。 App的ApiClient负责进行API调用,知道要定位的URL。我希望ApiClient知道API的URL,并且请求将保留URN部分(资源名称)。它们一起构成完整的URI。 (这是可选的,只是期待API版本。)
namespace App;
class ApiClient implements \Api\Client {
private static $url = 'https://api.yourapp.tld';
/**
* Just an example implementation using json (not completed)
*/
public function call($method, $uri, array $params = array()) {
$cUrlHandle = \curl_init(self::$url . '/' . $uri);
\curl_setopt($cUrlHandle, CURLOPT_CUSTOMREQUEST, $method);
\curl_setopt($cUrlHandle, CURLOPT_RETURNTRANSFER, true);
if (!empty($params)) {
\curl_setopt($cUrlHandle, CURLOPT_POSTFIELDS, \json_encode($params));
}
$response = curl_exec($cUrlHandle);
//...
}
}
现在我们可以创建不同类型的请求。每个人都负责验证和打包API客户端的参数。
我注意到所有更新请求都需要id。我会用它来处理一个对象的创建和更新请求(如果不可能,你可以拆分它们)。
class ImageLayerRequest implements \Api\Request {
private $id;
private $url;
private $apiUrn;
private $params = array();
/**
* If $id provided it's an update request otherwise it'll be create
*
* @param string $id
* @param string $imageUrl
*/
public function __construct($id, $imageUrl) {
$this->id = $id;
$this->url = $imageUrl;
}
public function isValid() {
if ($this->id === null) {
//validate create request
//...
$this->apiUrn = 'image-layer/create';
} else {
//validate update request
//...
$this->params['id'] = $this->id;
$this->apiUrn = 'image-layer/update';
}
$this->params['url'] = $this->url;
}
public function make(\Api\Client $client) {
return $client->call('post', $this->apiUrn, $this->params);
}
}
对于AudioLayer:
class AudioLayerRequest implements \Api\Request {
private $id;
private $bitrate;
private $url;
//the rest is similar, just diferent parameters
}