要统一多个不同但部分逻辑相似的接口成一个 API 接口,可以采用策略模式(Strategy Pattern)来实现。这种设计模式允许你定义一组算法,将它们封装起来,并且使它们可以互相替换。策略模式使得算法可以独立于使用它的客户而变化。

步骤

  1. 定义策略接口
  2. 实现具体策略
  3. 创建策略上下文类
  4. 在控制器中使用策略上下文类
  5. 配置路由

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.phproutes/api.php 中配置路由:

1
2
3
use App\Http\Controllers\PointsController;

Route::post('/points/deduct/{user}', [PointsController::class, 'deductPoints']);

总结

通过以上步骤,我们将多个不同的扣积分接口统一成一个 API 接口。我们使用策略模式来定义和实现不同的扣积分逻辑,根据请求的参数选择合适的策略,从而实现统一的接口。这样不仅减少了代码重复,还提高了代码的可维护性和可扩展性。