要统一多个不同但部分逻辑相似的接口成一个 API 接口,可以采用策略模式(Strategy Pattern)来实现。这种设计模式允许你定义一组算法,将它们封装起来,并且使它们可以互相替换。策略模式使得算法可以独立于使用它的客户而变化。
步骤
- 定义策略接口
- 实现具体策略
- 创建策略上下文类
- 在控制器中使用策略上下文类
- 配置路由
1. 定义策略接口
首先,定义一个策略接口,所有具体的扣积分策略都将实现这个接口。
1
2
3
4
5
6
7
8
9
10
11
<?php
namespace App\Services\Points;
use App\Models\User;
use Illuminate\Http\Request;
interface PointsStrategy
{
public function execute(User $user, Request $request): bool;
}
2. 实现具体策略
为每个不同的扣积分操作实现具体的策略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
namespace App\Services\Points;
use App\Models\User;
use Illuminate\Http\Request;
class CouponDeductPointsStrategy implements PointsStrategy
{
public function execute(User $user, Request $request): bool
{
// 具体的优惠券抵扣扣积分逻辑
// 检查优惠券是否有效
// 扣除积分
// 记录日志
return true;
}
}
class EnergyCouponDeductPointsStrategy implements PointsStrategy
{
public function execute(User $user, Request $request): bool
{
// 具体的元气优惠券抵扣扣积分逻辑
// 检查元气优惠券是否有效
// 扣除积分
// 记录日志
return true;
}
}
class MiniProgramCheckInDeductPointsStrategy implements PointsStrategy
{
public function execute(User $user, Request $request): bool
{
// 具体的小程序打卡扣积分逻辑
// 检查打卡是否有效
// 扣除积分
// 记录日志
return true;
}
}
class AdminAdjustPointsStrategy implements PointsStrategy
{
public function execute(User $user, Request $request): bool
{
// 具体的后台增加扣减积分逻辑
// 检查管理员权限
// 扣除或增加积分
// 记录日志
return true;
}
}
3. 创建策略上下文类
创建一个上下文类,用于根据请求选择合适的策略并执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
namespace App\Services\Points;
use Illuminate\Http\Request;
use App\Models\User;
class PointsContext
{
protected $strategy;
public function __construct(PointsStrategy $strategy)
{
$this->strategy = $strategy;
}
public function executeStrategy(User $user, Request $request): bool
{
return $this->strategy->execute($user, $request);
}
}
4. 在控制器中使用策略上下文类
在控制器中,根据请求中的参数选择合适的策略,并通过上下文类执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Services\Points\PointsContext;
use App\Services\Points\CouponDeductPointsStrategy;
use App\Services\Points\EnergyCouponDeductPointsStrategy;
use App\Services\Points\MiniProgramCheckInDeductPointsStrategy;
use App\Services\Points\AdminAdjustPointsStrategy;
use Illuminate\Http\Request;
class PointsController extends Controller
{
public function deductPoints(Request $request, User $user)
{
$type = $request->input('type'); // 请求中传入的类型参数
switch ($type) {
case 'coupon':
$strategy = new CouponDeductPointsStrategy();
break;
case 'energy_coupon':
$strategy = new EnergyCouponDeductPointsStrategy();
break;
case 'mini_program_checkin':
$strategy = new MiniProgramCheckInDeductPointsStrategy();
break;
case 'admin_adjust':
$strategy = new AdminAdjustPointsStrategy();
break;
default:
return response()->json(['message' => 'Invalid type.'], 400);
}
$context = new PointsContext($strategy);
$success = $context->executeStrategy($user, $request);
if ($success) {
return response()->json(['message' => 'Operation successful.']);
}
return response()->json(['message' => 'Operation failed.'], 400);
}
}
5. 配置路由
在 routes/web.php
或 routes/api.php
中配置路由:
1
2
3
use App\Http\Controllers\PointsController;
Route::post('/points/deduct/{user}', [PointsController::class, 'deductPoints']);
总结
通过以上步骤,我们将多个不同的扣积分接口统一成一个 API 接口。我们使用策略模式来定义和实现不同的扣积分逻辑,根据请求的参数选择合适的策略,从而实现统一的接口。这样不仅减少了代码重复,还提高了代码的可维护性和可扩展性。