一个类只做一件事
说明#
本文主要结合代码说明如何去在写代码时做到 一个类只做一件事
。
需求#
实现一个 cURL
类,针对不同平台的 API
进行操作,并最终返回 array
给方法的调用方。
思路#
分析需求设计到的功能点:
cURL
操作类- 不同平台的验证规则可能不一样,所以每一个平台都应该对应一个类
cURL
请求一般返回的是字符串,需要将结果转化为array
实现#
-
定义好
CurlInterfaceDriver
类的Interface
规范。主要定义三个常用方法
namespace App\Curl\bin; interface CurlInterfaceDriver { public function get($url, $options = []); public function post($url, $options = []); public function request($method, $url, $options = []); }
-
实现抽象类
AbstractHttpCurlDriver
namespace App\Curl\bin; use GuzzleHttp\Client; abstract class AbstractHttpCurlDriver implements CurlInterfaceDriver { /** * @var null|Client */ protected $client = null; protected $response = null; public function __construct(Client $client = null) { if (is_null($client)) { $client = new Client(); } $this->setClient($client); } /** * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function get($url, $options = []) { $response = $this->getClient()->request('GET', $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function post($url, $options = []) { $response = $this->getClient()->request('POST', $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @param $method * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function request($method, $url, $options = []) { $response = $this->getClient()->request($method, $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @return null|Client */ private function getClient() { return $this->client; } /** * @param Client $client */ private function setClient(Client $client) { $this->client = $client; } /** * @return null|string */ public function getResponse() { return $this->response; } /** * @param null|string $response */ private function setResponse($response) { $this->response = $response; } }
-
每个平台返回数据格式可能不一样,所以抽象类中只将结果字符串返回,针对不同返回数据格式,我们可以创建不同的
Driver
继承AbstractHttpCurlDriver
针对
JSON
返回结果的类。namespace App\Curl\bin; class JsonHttpCurlDriver extends AbstractHttpCurlDriver { }
针对
XML
返回结果的类。namespace App\Curl\bin; class XMLHttpCurlDriver extends AbstractHttpCurlDriver { }
因为
JSON
和XML
两个驱动的只有返回结果不一样,其他内容基本一样,所以不用在自己类里面改写抽象类里面的东西。 -
实现将
response
转换为array
的类根据使用的
driver
自动转换结果。namespace App\Curl\bin; use App\Exceptions\ResponseNotJsonException; use App\Exceptions\ResponseNotXMLException; use SimpleXMLElement; class ApiData2ArrayFactory { public static function make(CurlInterfaceDriver $curl) { if ($curl instanceof JsonHttpCurlDriver) { return static::json2Array($curl->getResponse()); } if ($curl instanceof XMLHttpCurlDriver) { return static::xml2Array($curl->getResponse()); } } /** * json 转数组 * * @param $json * @return array * @date 2019/01/25 * @author ycz * @throws ResponseNotJsonException */ private static function json2Array($json) { try { $data = \GuzzleHttp\json_decode($json, true); } catch (\InvalidArgumentException $e) { throw new ResponseNotJsonException(); } return $data; } /** * @param $xml * @return array * @date 2019/01/25 * @author ycz * @throws ResponseNotXMLException */ private static function xml2Array($xml) { if (!static::isXml($xml)) { throw new ResponseNotXMLException(); } function _XML2Array(SimpleXMLElement $parent) { $array = array(); foreach ($parent as $name => $element) { ($node = &$array[$name]) && (1 === count($node) ? $node = array($node) : 1) && $node = &$node[]; $node = $element->count() ? _XML2Array($element) : trim($element); } return $array; } $xml = new SimpleXMLElement($xml); $data = _XML2Array($xml); return $data; } /** * @param $xml * @return int * @date 2019/01/25 * @author ycz */ private static function isXml($xml) { return xml_parse(xml_parser_create(), $xml, true); } }
-
实现对外调用的
cURL
类namespace App\Curl\bin; /** * Class Curl * * @package App\Curl\bin * @method get * @method post * @method request * @see AbstractHttpCurlDriver */ class Curl { private $curlDriver = null; public function __construct(CurlInterfaceDriver $curl) { $this->curlDriver = $curl; } public function __call($name, $arguments) { $this->curlDriver->$name(...$arguments); return ApiData2ArrayFactory::make($this->curlDriver); } }
-
实现单个平台的
cURL
类,以亚马孙为例,我们创建一个AmazonCurl
namespace App\Curl\Amazon; use App\Curl\BaseCurl; use App\Curl\bin\Curl; use App\Curl\bin\JsonHttpCurlDriver; class AmazonCurl extends BaseCurl { public function __construct() { $this->curl = new Curl(new JsonHttpCurlDriver());//假设亚马逊返回的是 json 数据 } public function getProductList() { return $this->curl->get('http://amazon.com/get-product-list',[]); } }
-
外部调用
$amazonCurl = new AmazonCurl(); return $amazonCurl->getProductList();
-
说明
如果哪天亚马逊的接口返回变成了
XML
数据,我们只用将AmazonCurl
构造函数中的JsonHttpCurlDriver
替换为XMLHttpCurlDriver
即可。后续如果新增了其他格式的数据返回,支持新数据只用实现两个东西:1. 继承于
AbstractHttpCurlDriver
的驱动类。2. 在ApiData2ArrayFactory
实现改格式转array
的方法。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: