Skip to content

Commit 76611d7

Browse files
committed
feat(Chain Of Responsibilities): code & test & readme
1 parent 4bad149 commit 76611d7

File tree

7 files changed

+172
-3
lines changed

7 files changed

+172
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Behavioral\ChainOfResponsibilities;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
7+
abstract class Handler
8+
{
9+
/**
10+
* @var Handler
11+
*/
12+
private $successor = null;
13+
14+
public function __construct(Handler $handler = null)
15+
{
16+
$this->successor = $handler;
17+
}
18+
19+
/**
20+
* 确保了每个子类都不会忘记调用后续处理
21+
*/
22+
final public function handle(RequestInterface $request): ?string
23+
{
24+
$processed = $this->processing($request);
25+
26+
if ($processed === null && $this->successor !== null) {
27+
$processed = $this->successor->handle($request);
28+
}
29+
30+
return $processed;
31+
}
32+
33+
abstract protected function processing(RequestInterface $request): ?string;
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Behavioral\ChainOfResponsibilities;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
7+
class HttpInMemoryCacheHandler extends Handler
8+
{
9+
/**
10+
* @var array
11+
*/
12+
private $data;
13+
14+
public function __construct(array $data, ?Handler $successor = null)
15+
{
16+
parent::__construct($successor);
17+
18+
$this->data = $data;
19+
}
20+
21+
protected function processing(RequestInterface $request): ?string
22+
{
23+
$key = sprintf(
24+
'%s?%s',
25+
$request->getUri()->getPath(),
26+
$request->getUri()->getQuery()
27+
);
28+
29+
if ($request->getMethod() == 'GET' && isset($this->data[$key])) {
30+
return $this->data[$key];
31+
}
32+
33+
return null;
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Behavioral\ChainOfResponsibilities;
4+
5+
use Psr\Http\Message\RequestInterface;
6+
7+
class SlowDatabaseHandler extends Handler
8+
{
9+
protected function processing(RequestInterface $request): ?string
10+
{
11+
// 模拟数据返回, 生产状态下是查询数据库的结果.
12+
return 'Hello World!';
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Behavioral\ChainOfResponsibilities\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Psr\Http\Message\RequestInterface;
7+
use Psr\Http\Message\UriInterface;
8+
use Behavioral\ChainOfResponsibilities\Handler;
9+
use Behavioral\ChainOfResponsibilities\HttpInMemoryCacheHandler;
10+
use Behavioral\ChainOfResponsibilities\SlowDatabaseHandler;
11+
12+
class ChainTest extends TestCase
13+
{
14+
/**
15+
* @var Handler
16+
*/
17+
private $chain;
18+
19+
protected function setUp(): void
20+
{
21+
$this->chain = new HttpInMemoryCacheHandler(
22+
['/test?a=1' => 'Hello In Memory!'],
23+
new SlowDatabaseHandler()
24+
);
25+
}
26+
27+
public function testCanRequestKeyInFastStorage()
28+
{
29+
$uri = $this->createMock(UriInterface::class);
30+
$uri->method('getPath')->willReturn('/test');
31+
$uri->method('getQuery')->willReturn('a=1');
32+
33+
$request = $this->createMock(RequestInterface::class);
34+
$request->method('getMethod')
35+
->willReturn('GET');
36+
$request->method('getUri')->willReturn($uri);
37+
38+
$this->assertSame('Hello In Memory!', $this->chain->handle($request));
39+
}
40+
41+
public function testCanRequestKeyInSlowStorage()
42+
{
43+
$uri = $this->createMock(UriInterface::class);
44+
$uri->method('getPath')->willReturn('/foo');
45+
$uri->method('getQuery')->willReturn('');
46+
47+
$request = $this->createMock(RequestInterface::class);
48+
$request->method('getMethod')
49+
->willReturn('GET');
50+
$request->method('getUri')->willReturn($uri);
51+
52+
$this->assertSame('Hello World!', $this->chain->handle($request));
53+
}
54+
}

Behavioral/README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# 行为型模式
2+
3+
这些设计模式特别关注**对象之间的通信**
4+
增加了执行通信的灵活性。
5+
6+
## 责任链模式
7+
8+
* 简介
9+
10+
为请求创建了一个接收者对象的链。
11+
通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
12+
13+
* 优点:
14+
1. 降低耦合度。它将请求的发送者和接收者解耦。
15+
2. 简化了对象。使得对象不需要知道链的结构。
16+
3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
17+
4. 增加新的请求处理类很方便。
18+
19+
* 缺点:
20+
1. 不能保证请求一定被接收。
21+
2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
22+
3. 可能不容易观察运行时的特征,有碍于除错。
23+
24+
* 使用场景:
25+
1. 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
26+
2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
27+
3. 可动态指定一组对象处理请求。
28+
29+
* 示例
30+
31+
> 场景:请求接口数据, 缓存上未找到, 委托给数据库查询接口。

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
- [x] 数据映射
2727
- [x] 依赖注入
2828

29-
## 行为型
29+
## 行为型(./Behavioral/README.md)
3030

31-
- [ ] 责任链模式
31+
- [x] 责任链模式
3232
- [ ] 命令模式
3333
- [ ] 解释器模式
3434
- [ ] 迭代器模式

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
],
1111
"minimum-stability": "stable",
1212
"require": {
13-
"php": ">=7"
13+
"php": ">=7.2",
14+
"psr/http-message": "^1.0"
1415
},
1516
"require-dev": {
1617
"phpunit/phpunit": "^8"

0 commit comments

Comments
 (0)