目录
创造模式
一. 工厂方法模式
1. Eloquent ORM 模型工厂
2. 表单请求工厂
3. 服务容器中的工厂方法
二. 抽象工厂模式
1. 配置文件
2. 服务提供者
3. 门面(Facades)
4. 多环境配置
5. 依赖注入容器
三.原型模式
1. 配置对象的复制
2. 请求和响应的快速复制
3. 会话管理
4. 数据模型的快速复制
5. 缓存数据的复制
四. 建造者模式
1. 表单和HTML的构建
2. 查询构建器
3. 邮件消息构建
4. 视图组件和插槽
5. 集合操作
6. 表单请求验证
五. 单例模式
1. 服务容器
2. 门面(Facades)
3. 配置和环境
4. 日志
5. 路由服务
6. 会话管理
7. 缓存管理
8. 应用实例
结构型模式
一 .享元模式
1. 配置对象的共享
2. 数据库连接的共享
3. 缓存对象的共享
4. 会话对象的共享
5. 路由参数对象的共享
6. 视图组件的共享
二.桥接模式
1. 服务容器和具体服务实现
2. 门面与底层服务
3. 路由和请求处理器
4. 表单请求和验证逻辑
5. 视图组件和视图类
6. 事件和监听器
7. 策略模式实现
三. 适配器模式
1. 数据库连接适配器
2. 缓存存储适配器
3. 队列驱动适配器
4. 邮件发送适配器
5. 事件和监听器
6. 服务提供者适配器
7. 第三方包集成
四. 代理模式
1. 门面(Facades)
2. 服务容器和服务提供者
3. 事件监听器
4. 表单请求
5. 路由中间件
6. 模型事件
7. 队列和作业
五. 外观模式
1. 门面(Facades)
2. 服务提供者
3. 路由文件
4. 视图组件
5. 表单宏
6. 配置文件
7. 助手函数
六. 装饰模式
1. 中间件(Middleware)
2. 服务提供者(Service Providers)
3. 视图组件和指令
4. 模型事件
5. 表单请求扩展
6. 资源类(Resource)
7. 缓存装饰者
七. 组合模式
1. 分类系统
2. 权限和角色管理系统
3. 多级菜单
4. 组织结构
5. 文件系统
行为型模式
一. 模板模式
1. 控制器方法
2. 服务提供者(Service Providers)
3. 命令模式(Command Pattern)
4. 事件和监听器
5. 邮件发送
6. 队列作业(Queueable Jobs)
7. 测试案例
创造模式
一. 工厂方法模式
(Factory Method Pattern)是一种创建型设计模式,它提供了一种在不指定具体类的情况下创建对象的方法。这种模式允许一个类的实例化延迟到子类中进行,使得子类能够改变一个对象的类型。
在 Laravel 框架中,工厂方法模式被广泛应用于模型(Eloquent ORM)和请求(Form Request)的创建过程中。
1. Eloquent ORM 模型工厂
Laravel 的 Eloquent ORM 提供了一种非常方便的方式来创建和存储数据。模型工厂用于生成测试数据。每个模型通常有一个对应的工厂类,这个类继承自 Illuminate\Database\Eloquent\Factories\Factory
。
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* 定义模型的默认状态。
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
}
使用工厂生成数据:
$user = User::factory()->create();
2. 表单请求工厂
Laravel 的表单请求也支持工厂方法模式。你可以创建一个工厂类来生成表单请求的实例,这在测试时非常有用。
use Illuminate\Support\Facades\Hash;
use App\Models\User;
class UserRequestFactory
{
public static function create(array $attributes = [])
{
$user = User::factory()->create($attributes);
return new StoreUserRequest([
'name' => $user->name,
'email' => $user->email,
'password' => Hash::make('password'),
]);
}
}
使用工厂创建请求:
$request = UserRequestFactory::create();
3. 服务容器中的工厂方法
Laravel 的服务容器也使用了工厂方法模式。你可以在服务提供者中绑定一个接口到其具体实现的工厂方法。
$this->app->bind(CacheStore::class, function ($app) {
return new RedisCacheStore();
});
然后,你可以在应用程序中通过服务容器解析这个接口,得到具体的实现。
$cacheStore = app(CacheStore::class);
工厂方法模式在 Laravel 中的使用提高了代码的可维护性和可测试性,同时也使得对象的创建更加灵活和可配置。
二. 抽象工厂模式
(Abstract Factory Pattern)是一种创建型设计模式,它允许创建一系列相关或依赖对象,而无需指定它们具体的类。这种模式提供了一种方式,可以保证客户端使用与抽象工厂提供的接口兼容的产品族。
在 Laravel 框架中,虽然抽象工厂模式不像工厂方法模式那样直接明显,但是它的思想在某些方面得到了应用。以下是一些可能的抽象工厂模式的应用场景:
1. 配置文件
Laravel 的配置文件可以看作是一种抽象工厂。配置文件定义了应用程序的设置,但是具体的实现细节(如数据库连接、缓存驱动等)可以在运行时根据配置文件来创建。
// config/database.php
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'mysql' => [
// MySQL 连接配置
],
'pgsql' => [
// PostgreSQL 连接配置
],
],
];
应用程序根据配置文件创建具体的数据库连接:
$connection = DB::connection($connectionName);
2. 服务提供者
Laravel 的服务提供者(Service Provider)可以被视为抽象工厂的一种形式。服务提供者负责在应用程序的生命周期中注册服务和类绑定,但是具体的实现细节是在服务提供者内部定义的。
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册服务
}
public function boot()
{
// 启动服务
}
}
3. 门面(Facades)
Laravel 的门面(Facades)也可以看作是一种抽象工厂。门面提供了一个“静态”接口来访问更复杂的服务逻辑,而这些服务的具体实现是在服务容器中定义的。
// 使用门面访问服务
// 使用门面访问服务
Cache::put('key', 'value', $minutes);
4. 多环境配置
在 Laravel 中,你可以为不同的环境(如开发、测试、生产)定义不同的配置。这可以通过环境特定的配置文件实现,这些配置文件充当了抽象工厂的角色,为不同环境创建不同的配置实例。
// .env 文件
APP_ENV=local
// config/app.php
return [
'env' => env('APP_ENV', 'production'),
];
根据环境变量 APP_ENV
的值,应用程序将使用不同的配置。
5. 依赖注入容器
Laravel 的依赖注入容器(Service Container)本身可以被视为一个抽象工厂。容器负责创建对象的实例,但是具体的创建逻辑是在容器内部定义的,并且可以在运行时动态地改变。
$this->app->bind('MyInterface', 'MyClass');
// 使用容器解析接口
$myService = app('MyInterface');
虽然 Laravel 没有直接实现一个抽象工厂类,但是它的许多组件和设计原则都体现了抽象工厂模式的思想,即通过定义一个创建对象的接口,让子类决定实例化哪一个类。这有助于提高代码的灵活性和可扩展性。
三.原型模式
(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有的实例(原型)来创建新的实例,而不是通过新建实例。这种模式特别适用于创建复杂对象,或者当对象的创建成本很高时。
在 Laravel 中,原型模式的应用并不像其他设计模式那样常见,因为 Laravel 的设计哲学更倾向于使用服务容器和依赖注入来管理对象的生命周期。然而,原型模式的思想仍然可以在某些情况下被应用,尤其是在需要快速复制对象时。
以下是一些可能的原型模式应用场景:
1. 配置对象的复制
在 Laravel 中,配置对象可能包含大量的数据,创建这些对象可能代价昂贵。通过原型模式,可以首先创建一个配置对象的实例,然后复制这个实例来创建新的配置对象。
class Config {
protected $data;
public function __construct(array $data) {
$this->data = $data;
}
public function cloneData() {
return clone $this;
}
}
$config = new Config(/* 复杂数据 */);
$newConfig = $config->cloneData();
2. 请求和响应的快速复制
在处理 HTTP 请求和响应时,有时可能需要快速复制现有的请求或响应对象,以便进行修改或重用。
class Config {
protected $data;
public function __construct(array $data) {
$this->data = $data;
}
public function cloneData() {
return clone $this;
}
}
$config = new Config(/* 复杂数据 */);
$newConfig = $config->cloneData();
3. 会话管理
在会话管理中,可能需要复制会话数据以进行不同的操作,而不影响原始会话。
class Session {
protected $data;
public function __construct(array $data) {
$this->data = $data;
}
public function cloneSession() {
return clone $this;
}
}
$session = new Session(/* 会话数据 */);
$newSession = $session->cloneSession();
4. 数据模型的快速复制
在处理数据模型时,可能需要复制模型实例以进行测试或其他操作。
class Model {
// 模型数据...
public function cloneModel() {
return clone $this;
}
}
$model = new Model(/* 模型数据 */);
$newModel = $model->cloneModel();
5. 缓存数据的复制
在缓存系统中,可能需要复制缓存项以进行不同的处理。
class CacheItem {
protected $value;
public function __construct($value) {
$this->value = $value;
}
public function cloneCacheItem() {
return clone $this;
}
}
$cacheItem = new CacheItem(/* 缓存数据 */);
$newCacheItem = $cacheItem->cloneCacheItem();
在 Laravel 中,虽然原型模式不是主要的设计模式,但是通过使用 PHP 的 clone
关键字,可以在需要时实现对象的快速复制。这种方式可以减少创建复杂对象的开销,提高应用程序的性能。然而,需要注意的是,原型模式可能会增加内存的使用,因此在内存敏感的应用中应谨慎使用。
四. 建造者模式
(Builder Pattern)是一种创建型设计模式,用于创建一个复杂的对象,同时允许用户只通过指定复杂对象的类型和内容就能构建它们,隐藏了内部的构建细节。
在 Laravel 中,建造者模式主要体现在几个方面:
1. 表单和HTML的构建
Laravel 提供了一个强大的 HTML 和表单构建类,这些类使用建造者模式来创建 HTML 元素和表单。例如,使用 Form
和 Html
facades 可以构建复杂的表单和 HTML 结构。
use Illuminate\Support\Facades\Form;
use Illuminate\Support\Facades\Html;
// 创建一个文本输入框
echo Form::text('username');
// 创建一个下拉选择框
echo Form::select('gender', ['male' => 'Male', 'female' => 'Female']);
// 创建一个复选框
echo Form::checkbox('terms', '1');
2. 查询构建器
Laravel 的 Eloquent ORM 和查询构建器(Query Builder)也使用了建造者模式。它们允许开发者以链式调用的方式构建复杂的数据库查询。
use App\Models\User;
// 构建一个查询来获取所有活跃的用户
$users = User::where('active', 1)
->orderBy('created_at', 'desc')
->get();
3. 邮件消息构建
Laravel 的邮件系统允许开发者构建邮件消息,通过链式方法调用设置邮件的各个部分。
use Illuminate\Support\Facades\Mail;
Mail::send('emails.welcome', $data, function ($message) use ($user) {
$message->to($user->email)
->subject('Welcome to Our Application');
});
4. 视图组件和插槽
Laravel 的 Blade 模板引擎支持组件和插槽,它们可以用来构建复杂的视图结构。组件可以接收数据和方法,然后构建视图。
<x-alert type="success">
{{ $slot }}
</x-alert>
<x-alert type="success">
@slot('default')
This is a success message!
@endslot
</x-alert>
5. 集合操作
Laravel 的集合类(Collection)也使用了建造者模式。集合操作允许开发者对数据集合进行链式操作。
use Illuminate\Support\Collection;
$collection = collect([1, 2, 3, 4, 5]);
$filtered = $collection->filter(function ($value) {
return $value > 2;
});
6. 表单请求验证
Laravel 的表单请求验证也采用了建造者模式。表单请求类允许开发者链式地定义验证规则。
use Illuminate\Foundation\Http\FormRequest;
class StoreBlogPost extends FormRequest
{
public function rules()
{
return [
'title' => 'required|max:255',
'body' => 'required',
];
}
}
建造者模式在 Laravel 中被广泛使用,它提供了一种清晰和灵活的方式来构建复杂的对象和结构。通过链式调用,开发者可以以一种声明性的方式构建对象,同时隐藏了实现细节,使得代码更加简洁和易于维护。
五. 单例模式
(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这种模式通常用于需要全局状态或者需要频繁访问的资源。
在 Laravel 中,单例模式的应用主要体现在以下几个方面:
1. 服务容器
Laravel 的服务容器(Service Container)本身就是一个单例。它在整个应用程序的生命周期中只创建一次,并被所有服务提供者和依赖注入所共享。
$app = app(); // 获取服务容器的单例实例
2. 门面(Facades)
Laravel 的门面(Facades)提供了一个“静态”接口来访问服务容器中的单例服务。例如,DB
门面是数据库服务的单例访问点。
use Illuminate\Support\Facades\DB; DB::table('users')->get();
// 访问数据库服务的单例实例
3. 配置和环境
Laravel 的配置和环境设置也是单例模式的应用。配置文件在整个应用程序中只加载一次,然后被缓存起来供全局访问。
$env = config('app.env'); // 获取环境配置的单例数据
4. 日志
Laravel 的日志服务是另一个单例模式的例子。日志服务在整个应用程序中只实例化一次,并用于记录日志信息。
use Illuminate\Support\Facades\Log; Log::info('This is an info message.'); // 使用日志服务的单例实例
5. 路由服务
Laravel 的路由服务也是一个单例,它负责注册和解析应用程序的路由。
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return 'Hello World';
});
6. 会话管理
会话管理器(Session Manager)在 Laravel 中也是一个单例,它负责处理用户的会话数据。
use Illuminate\Support\Facades\Session;
Session::put('key', 'value'); // 操作会话数据的单例实例
7. 缓存管理
缓存管理器(Cache Manager)在 Laravel 中同样是一个单例,用于处理缓存数据。
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', $ttl); // 使用缓存服务的单例实例
8. 应用实例
app()
函数是获取 Laravel 应用实例的单例访问点。
$app = app(); // 获取 Laravel 应用的单例实例
单例模式在 Laravel 中被广泛使用,主要是因为它提供了一种简单的方式来管理全局状态和资源,同时确保了资源的一致性和效率。然而,过度使用单例模式可能会导致代码难以测试和维护,因此在设计应用程序时应谨慎考虑。
结构型模式
一 .享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享来高效地管理大量细粒度的对象。这种模式非常适合于当对象的创建成本很高,或者对象数量非常多,以至于内存消耗成为问题时使用。
在 Laravel 中,享元模式的应用可能不是直接显而易见的,因为 Laravel 的设计哲学更倾向于使用服务容器和依赖注入来管理对象的生命周期。然而,享元模式的思想可以在一些场景中得到应用,尤其是在需要高效管理大量相似对象时。
以下是一些可能的享元模式应用场景:
1. 配置对象的共享
在 Laravel 中,配置对象可能包含大量的数据,并且多个地方可能需要使用相同的配置数据。通过享元模式,可以共享相同的配置对象实例,而不是为每个使用场景创建新的实例。
class Config {
protected $data;
public function __construct(array $data) {
$this->data = $data;
}
public static function getInstance(array $data) {
static $instances = [];
$key = md5(serialize($data));
if (!isset($instances[$key])) {
$instances[$key] = new self($data);
}
return $instances[$key];
}
}
$config = Config::getInstance(/* 配置数据 */);
2. 数据库连接的共享
Laravel 的数据库连接可以使用享元模式来共享,特别是当使用相同的连接配置时。这样可以减少创建多个相同配置的数据库连接的开销。
class DatabaseConnection {
// 数据库连接逻辑
}
$connection = DatabaseConnection::getInstance(/* 连接配置 */);
3. 缓存对象的共享
在 Laravel 中,缓存对象可以通过享元模式来共享,以避免重复创建相同的缓存键。
class CacheItem {
// 缓存项逻辑
}
$cacheItem = CacheItem::getInstance(/* 缓存键 */);
4. 会话对象的共享
会话管理中,可以使用享元模式来共享会话对象,特别是当多个用户具有相同的会话数据时。
class Session {
// 会话逻辑
}
$session = Session::getInstance(/* 会话ID */);
5. 路由参数对象的共享
在处理路由时,Laravel 可以共享具有相同参数的路由对象,以减少对象创建的开销。
class RouteParameter {
// 路由参数逻辑
}
$routeParameter = RouteParameter::getInstance(/* 参数数据 */);
6. 视图组件的共享
在 Blade 模板中,可以使用享元模式来共享具有相同属性的视图组件。
@component('component-name', ['shared' => true])
<!-- 组件内容 -->
@endcomponent
享元模式在 Laravel 中的使用可以提高应用程序的性能,尤其是在处理大量相似对象时。然而,需要注意的是,享元模式可能会导致对象状态管理的复杂性增加,因为共享的对象需要确保它们的状态是线程安全的,并且在多个地方使用时不会相互影响。在设计应用程序时,应该根据实际需求和上下文来决定是否使用享元模式。
二.桥接模式
(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。这种模式创建了一个抽象层,允许独立地扩展抽象和实现。
在 Laravel 中,桥接模式可以用于多种场景,尤其是在需要将功能和实现分离以提供灵活性和扩展性时。以下是一些可能的桥接模式应用场景:
1. 服务容器和具体服务实现
Laravel 的服务容器允许你将接口(抽象)与具体的服务实现分离。这使得你可以在运行时动态地替换服务的实现。
// 定义一个抽象接口
interface LoggerInterface {}
// 实现该接口的具体类
class FileLogger implements LoggerInterface {}
// 在服务容器中绑定接口到具体实现
$container->bind(LoggerInterface::class, FileLogger::class);
// 使用时,通过接口引用具体实现
$logger = app(LoggerInterface::class);
2. 门面与底层服务
Laravel 的门面(Facades)提供了一个“静态”接口来访问底层服务。门面定义了抽象的接口,而具体的实现则在服务容器中。
// 定义路由
Route::get('/', 'HomeController@index');
// 请求处理器实现
class HomeController
{
public function index()
{
return 'Hello World';
}
}
3. 路由和请求处理器
Laravel 的路由系统允许你将路由定义(抽象)与请求的处理逻辑(实现)分离。
// 定义路由
Route::get('/', 'HomeController@index');
// 请求处理器实现
class HomeController
{
public function index()
{
return 'Hello World';
}
}
4. 表单请求和验证逻辑
Laravel 的表单请求(Form Request)允许你将验证逻辑(实现)与控制器(抽象)分离。
// 表单请求类作为验证逻辑的实现
class StorePostRequest extends FormRequest
{
public function rules()
{
return [
'title' => 'required|max:255',
'body' => 'required',
];
}
}
// 控制器作为抽象层
class PostController extends Controller
{
public function store(StorePostRequest $request)
{
// 验证逻辑由 StorePostRequest 处理
}
}
5. 视图组件和视图类
Laravel 的 Blade 模板引擎支持组件,你可以将组件的抽象定义与具体的视图逻辑分离。
{{-- 组件类定义 --}}
@component('alert', ['type' => 'success'])
{{ $slot }}
@endcomponent
{{-- 使用组件 --}}
<x-alert type="success">
这是一个成功消息!
</x-alert>
6. 事件和监听器
Laravel 的事件系统允许你将事件定义(抽象)与监听器的实现分离。
// 定义事件
event(new UserRegistered($user));
// 监听器实现
class UserRegisteredHandler
{
public function handle($event)
{
// 处理逻辑
}
}
7. 策略模式实现
策略模式(Strategy Pattern)通常与桥接模式结合使用,以实现算法族和封装它们的变化独立于使用它们的客户端。
// 定义策略接口
interface ShippingStrategy {}
// 实现策略接口的具体策略
class FedExShipping implements ShippingStrategy {}
// 客户端使用策略
class Order
{
protected $shippingStrategy;
public function __construct(ShippingStrategy $strategy)
{
$this->shippingStrategy = $strategy;
}
public function ship()
{
// 使用策略
}
}
桥接模式在 Laravel 中的使用提供了一种灵活的方式来组织代码,使得抽象和实现可以独立地变化和扩展。这种模式有助于创建更加模块化和可维护的代码结构。
三. 适配器模式
(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间能够一起工作。通过创建一个包装对象(适配器),它将一个类的接口转换成客户端期望的另一个接口。
在 Laravel 中,适配器模式的应用主要体现在以下几个方面:
1. 数据库连接适配器
Laravel 的 Eloquent ORM 使用适配器模式来连接不同类型的数据库。它提供了一个统一的接口来操作数据库,而具体的数据库连接实现则由不同的适配器来完成。
use Illuminate\Database\Capsule\Manager as DB;
$capsule = new DB;
$capsule->addConnection([
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]);
$capsule->setAsGlobal();
$capsule->bootEloquent();
2. 缓存存储适配器
Laravel 的缓存系统使用适配器模式来支持多种缓存后端,例如 Redis、Memcached 或文件缓存。通过适配器,Laravel 提供了一个统一的缓存接口。
use Illuminate\Support\Facades\Cache;
Cache::store('redis')->put('key', 'value', $minutes);
3. 队列驱动适配器
Laravel 的队列系统支持多种驱动,如数据库、Redis、Amazon SQS 等。每个队列驱动都是适配器模式的一个实现。
use Illuminate\Support\Facades\Queue;
Queue::connection('redis')->push(new Job());
4. 邮件发送适配器
Laravel 的邮件发送功能支持多种邮件发送服务,如 SMTP、Mailgun、Sendmail 等。每个邮件发送服务都是一个适配器。
use Illuminate\Support\Facades\Mail;
Mail::send('emails.welcome', $data, function ($message) use ($user) {
$message->to($user->email);
});
5. 事件和监听器
Laravel 的事件系统允许你定义事件和监听器,适配器模式在这里可以用于将事件转换为监听器期望的格式或类型。
use Illuminate\Support\Facades\Event;
class UserRegisteredEvent {}
class UserRegisteredListener
{
public function handle($event)
{
// 处理逻辑
}
}
Event::listen(UserRegisteredEvent::class, UserRegisteredListener::class);
6. 服务提供者适配器
Laravel 的服务提供者(Service Provider)可以看作是一种适配器,它将服务容器与服务的注册逻辑适配起来。
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册服务
}
public function boot()
{
// 启动服务
}
}
7. 第三方包集成
在集成第三方包时,适配器模式可以用来确保第三方包的接口与 Laravel 的接口兼容。
// 第三方包的类
class SomeThirdPartyClass {}
// 适配器类
class ThirdPartyAdapter implements SomeInterface
{
protected $thirdPartyClass;
public function __construct(SomeThirdPartyClass $thirdPartyClass)
{
$this->thirdPartyClass = $thirdPartyClass;
}
// 实现接口方法,委托给第三方类
public function someMethod()
{
// ...
}
}
适配器模式在 Laravel 中的使用有助于提高应用程序的灵活性和可扩展性,它允许开发者将现有的类和第三方库集成到 Laravel 应用程序中,而无需修改它们的源代码。通过适配器,可以保持代码的整洁和解耦。
四. 代理模式
(Proxy Pattern)是一种结构型设计模式,它为另一个对象提供一个代替或占位符,以控制对它的访问。代理可以在不改变对象的代码的情况下,增加额外的功能操作,例如延迟初始化、访问控制、日志记录、缓存等。
在 Laravel 中,代理模式的应用主要体现在以下几个方面:
1. 门面(Facades)
Laravel 的门面(Facades)可以被视为一种静态代理。门面提供了一个简单的方式来访问服务容器中的对象,而不需要直接从容器中解析它们。
// 使用门面来代理服务容器中的对象
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', 10);
2. 服务容器和服务提供者
Laravel 的服务容器使用代理模式来解析服务。当请求服务时,服务容器充当代理,根据配置创建或提供服务的实例。
$app = new Illuminate\Foundation\Application;
// 服务容器代理服务的解析
$app->bind("SomeInterface", function($app) {
return new SomeClass();
});
// 请求服务时,代理将提供实例
$service = $app->make("SomeInterface");
3. 事件监听器
Laravel 的事件系统可以看作是一种代理模式的应用。事件本身作为委托者,而事件监听器作为实际执行操作的代理。
use Illuminate\Support\Facades\Event;
class UserRegisteredEvent {}
class UserRegisteredEventListener
{
public function handle($event)
{
// 处理事件
}
}
// 注册事件和监听器
Event::listen(UserRegisteredEvent::class, [UserRegisteredEventListener::class, 'handle']);
4. 表单请求
Laravel 的表单请求(Form Request)可以被视为一种代理,它封装了验证逻辑,并代理到控制器。
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize()
{
// 授权逻辑
}
public function rules()
{
// 验证规则
}
}
// 控制器中使用表单请求
public function store(StorePostRequest $request)
{
// 请求已经通过验证
}
5. 路由中间件
Laravel 的路由中间件作为请求处理流程的代理,可以执行额外的逻辑,如认证、授权等,然后再将控制权传递给下一个中间件或最终的请求处理器。
Route::get('/home', function () {
// 首页
})->middleware('auth');
// 中间件作为代理执行认证逻辑
class AuthenticateMiddleware
{
public function handle($request, $next)
{
if (!Auth::check()) {
// 未认证,执行其他逻辑
}
return $next($request);
}
}
6. 模型事件
Laravel 的 Eloquent ORM 模型事件可以看作是一种代理模式。模型事件允许你在模型生命周期的关键点执行代码,代理模型的其他操作。
class User extends Model
{
protected static function boot()
{
parent::boot();
static::creating(function ($user) {
// 创建代理逻辑
});
}
}
7. 队列和作业
Laravel 的队列系统使用代理模式,作业(Job)类代理执行实际的工作,而队列系统负责作业的调度和执行。
use Illuminate\Support\Facades\Queue;
use App\Jobs\SendEmail;
// 将作业推送到队列
Queue::push(new SendEmail);
// 作业类作为代理执行发送邮件的操作
class SendEmail implements ShouldQueue
{
public function handle()
{
// 发送邮件的逻辑
}
}
五. 外观模式
(Facade Pattern)是一种结构型设计模式,它提供了一个统一的高层接口来访问子系统中的一群接口。外观模式定义了一个高层接口,这个接口使得子系统更容易使用。
在 Laravel 中,外观模式被广泛应用于简化应用程序中复杂逻辑的访问。以下是 Laravel 中外观模式的一些具体应用:
1. 门面(Facades)
Laravel 的门面是外观模式的一个典型例子。门面提供了一个简单、静态的接口来访问服务容器中的服务,隐藏了底层的复杂性。
// 使用门面访问服务容器中的服务
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', 10);
2. 服务提供者
Laravel 的服务提供者(Service Provider)也使用了外观模式。服务提供者定义了应用程序启动时需要执行的任务的高层接口,例如注册服务、事件监听器等。
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册服务
}
public function boot()
{
// 启动服务
}
}
3. 路由文件
Laravel 的路由文件(如 web.php
和 api.php
)作为外观模式,提供了一个集中的地方来定义所有请求的路由和控制器。
use Illuminate\Support\Facades\Route;
// 定义路由
Route::get('/', function () {
return view('welcome');
});
4. 视图组件
Laravel 的 Blade 模板引擎支持组件,这些组件可以看作是外观模式的实现,提供了一个简单的接口来封装复杂的视图逻辑。
{{-- 使用组件 --}}
<x-alert type="success" :messages="$messages" />
5. 表单宏
LaravelCollective 提供的宏(Macros)允许开发者扩展现有的门面功能,通过外观模式封装复杂的表单创建逻辑。
use Collective\Html\FormFacade as Form;
// 创建表单
{{ Form::open(['url' => 'post/create']) }}
{{ Form::text('title') }}
{{ Form::submit('Create') }}
{{ Form::close() }}
6. 配置文件
Laravel 的配置文件作为外观模式,提供了一个简单的接口来访问应用程序的配置设置。
// 访问配置
$debug = config('app.debug');
7. 助手函数
Laravel 提供了许多助手函数,这些函数作为外观模式,简化了常见的操作,如生成 URL、加密等。
// 生成 URL
$url = url('user/profile');
外观模式在 Laravel 中的使用,极大地简化了应用程序的复杂性,使得开发者可以更加专注于业务逻辑,而不必深入了解底层的实现细节。通过提供高层的接口,外观模式帮助开发者更容易地使用 Laravel 的强大功能。
六. 装饰模式
(Decorator Pattern)是一种结构型设计模式,允许用户向一个对象添加新的功能,同时不改变其结构。这种模式通过创建一个包装对象,包裹实际对象,来扩展对象的功能。
在 Laravel 中,装饰模式的应用可能不如其他模式那样明显,但是它的思想可以在多个地方找到。以下是一些可能的装饰模式应用场景:
1. 中间件(Middleware)
Laravel 的中间件可以被视为装饰模式的实现。中间件包装了 HTTP 请求的生命周期,可以在请求处理前后添加额外的行为。
namespace App\Http\Middleware;
use Closure;
class ExampleMiddleware
{
public function handle($request, Closure $next)
{
// 在处理请求之前添加逻辑
return $next($request);
// 在处理请求之后添加逻辑
}
}
2. 服务提供者(Service Providers)
服务提供者在 Laravel 中用于进行服务注册和启动逻辑,它们也可以被视为装饰者,因为它们扩展了应用程序的功能。
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册服务
}
public function boot()
{
// 启动服务
}
}
3. 视图组件和指令
Laravel 的 Blade 模板引擎支持组件和指令,这些组件可以看作是装饰者,因为它们扩展了视图的功能。
{{-- 使用 Blade 组件 --}}
<x-alert type="error" :messages="$errorMessages" />
4. 模型事件
Eloquent ORM 的模型事件允许在模型的生命周期中插入额外的行为,这可以被视为装饰模式的一种形式。
class User extends Model
{
protected static function boot()
{
parent::boot();
static::created(function ($user) {
// 用户创建后添加的逻辑
});
}
}
5. 表单请求扩展
表单请求可以扩展现有的验证逻辑,通过装饰模式添加额外的验证规则或授权检查。
class StorePostRequest extends FormRequest
{
public function rules()
{
return [
'title' => 'required|max:255',
// 添加额外的规则
];
}
}
6. 资源类(Resource)
API 资源类可以被视为装饰者,因为它们扩展了模型数据的表示方式,为 JSON 或其他格式的响应添加了额外的结构。
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
// 添加额外的数据
];
}
}
7. 缓存装饰者
Laravel 的缓存装饰者可以用于延迟初始化或增强缓存逻辑。
use Illuminate\Cache\CacheManager;
$cache = app('cache');
$decoratedCache = new SomeCacheDecorator($cache);
装饰模式在 Laravel 中的使用提高了代码的灵活性和可扩展性,允许开发者在不修改现有代码的情况下添加新功能。这种模式有助于保持代码的整洁和关注点分离。
七. 组合模式
(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
在 Laravel 中,组合模式可以用于多种场景,尤其是在需要表示层次结构数据时。以下是一些可能的组合模式应用场景:
1. 分类系统
如果你的应用程序有一个复杂的分类系统,你可以使用组合模式来表示这些分类。每个分类可以作为一个叶节点或组合节点。
class Category
{
protected $name;
protected $children = [];
public function __construct($name)
{
$this->name = $name;
}
public function add(Category $category)
{
$this->children[] = $category;
}
public function remove(Category $category)
{
// 逻辑来从 children 中移除一个分类
}
public function display()
{
foreach ($this->children as $child) {
echo $child->name;
$child->display();
}
}
}
2. 权限和角色管理系统
在权限和角色管理中,可以使用组合模式来表示不同角色可以拥有的权限集合。
class Permission
{
// 权限逻辑
}
class Role
{
protected $name;
protected $permissions = [];
public function __construct($name)
{
$this->name = $name;
}
public function addPermission(Permission $permission)
{
$this->permissions[] = $permission;
}
// 其他角色相关逻辑
}
3. 多级菜单
如果你的应用程序有一个多级菜单系统,组合模式可以用来构建和显示菜单项。
class MenuItem
{
protected $title;
protected $items = [];
public function __construct($title)
{
$this->title = $title;
}
public function add($item)
{
$this->items[] = $item;
}
public function render()
{
// 渲染当前菜单项和子菜单项
}
}
4. 组织结构
在表示公司的组织结构时,可以使用组合模式来表示不同层级的员工和团队。
class Employee
{
protected $name;
protected $subordinates = [];
public function __construct($name)
{
$this->name = $name;
}
public function addSubordinate(Employee $employee)
{
$this->subordinates[] = $employee;
}
public function report()
{
// 生成报告
}
}
5. 文件系统
在模拟文件系统时,可以使用组合模式来表示文件和文件夹的层次结构。
interface FileSystemElement
{
public function delete();
public function rename($newName);
}
class Folder implements FileSystemElement
{
protected $name;
protected $elements = [];
public function __construct($name)
{
$this->name = $name;
}
public function add(FileSystemElement $element)
{
$this->elements[] = $element;
}
// 实现 FileSystemElement 接口的方法
}
class File implements FileSystemElement
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
// 实现 FileSystemElement 接口的方法
}
组合模式在 Laravel 中的使用有助于简化对层次结构数据的操作,使得你可以统一地对待单个对象和组合对象。这种模式提高了代码的复用性,并使得层次结构的管理更加灵活和强大。
行为型模式
一. 模板模式
(Template Pattern)是一种行为型设计模式,它定义了算法的骨架,将一些步骤的执行延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。
在 Laravel 中,模板模式的概念被广泛应用,尤其是在框架的架构和组件设计中。以下是一些可能的模板模式应用场景:
1. 控制器方法
Laravel 控制器中的某些方法可以看作是模板方法。例如,资源控制器的方法遵循一个标准的 CRUD 模式。
class UserController extends Controller
{
// 展示用户列表
public function index()
{
// ...
}
// 展示单个用户
public function show($id)
{
// ...
}
// 创建新的用户页面
public function create()
{
// ...
}
// 存储新用户
public function store(Request $request)
{
// ...
}
// 编辑用户页面
public function edit($id)
{
// ...
}
// 更新用户
public function update(Request $request, $id)
{
// ...
}
// 删除用户
public function destroy($id)
{
// ...
}
}
2. 服务提供者(Service Providers)
服务提供者的 register
和 boot
方法遵循模板模式,允许开发者在这些方法中定义服务的注册和启动逻辑。
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// 注册服务到服务容器
}
public function boot()
{
// 执行启动逻辑,如事件注册、路由定义等
}
}