Design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design. It serves as a blueprint that can be implemented in your code to solve design challenges, promoting best practices and improving code maintainability, scalability, and readability.
1. MVC (Model-View-Controller)
The MVC pattern divides an application into three interconnected components:
- Model: Represents the data and business logic of the application. In Laravel, Eloquent ORM is used to interact with the database.
- View: Handles the presentation layer. Laravel's Blade templating engine simplifies the creation of dynamic views.
- Controller:Manages the user input and updates the model or view accordingly. Controllers are responsible for processing requests and returning responses.
Example
Model
The Product
model represents products in the database and
interacts with the products
table.
// app/Models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = ['name', 'price', 'description'];
}
View
The Blade view displays product information.
<!-- resources/views/products/index.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>Products</title>
</head>
<body>
<h1>Product List</h1>
@foreach ($products as $product)
<div>
<h2>{{ $product->name }}</h2>
<p>${{ $product->price }}</p>
<p>{{ $product->description }}</p>
</div>
@endforeach
</body>
</html>
Controller
The ProductController
fetches products from the model and passes
them to the view.
// app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
class ProductController extends Controller
{
public function index()
{
$products = Product::all();
return view('products.index', compact('products'));
}
}
Routes
Define a route for the controller action.
// routes/web.php
use App\Http\Controllers\ProductController;
Route::get('/products', [ProductController::class, 'index']);
2. Repository Pattern
The Repository Pattern abstracts data access logic, providing a clean API for interacting with data sources. This pattern decouples data access from business logic.
Repository Interface
Define methods for accessing user data.
// app/Repositories/UserRepositoryInterface.php
namespace App\Repositories;
interface UserRepositoryInterface
{
public function all();
public function find($id);
}
Repository Implementation
Implement the interface and interact with the User
model.
// app/Repositories/UserRepository.php
namespace App\Repositories;
use App\Models\User;
class UserRepository implements UserRepositoryInterface
{
public function all()
{
return User::all();
}
public function find($id)
{
return User::find($id);
}
}
Binding Repository
Bind the repository to the interface in a service provider.
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Repositories\UserRepositoryInterface;
use App\Repositories\UserRepository;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
}
Using the Repository
Inject the repository into a controller.
// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;
use App\Repositories\UserRepositoryInterface;
class UserController extends Controller
{
protected $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = $this->userRepository->all();
return view('users.index', compact('users'));
}
}
Routes
Define a route for the controller action.
// routes/web.php
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
3. Singleton Pattern
The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. Laravel’s service container often uses this pattern.
Service Class
Define a service class that handles configuration settings.
// app/Services/ConfigService.php
namespace App\Services;
class ConfigService
{
protected $settings;
public function __construct()
{
$this->settings = config('app.settings');
}
public function get($key)
{
return $this->settings[$key] ?? null;
}
}
Binding Singleton
Register the service as a singleton in a service provider.
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\ConfigService;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(ConfigService::class, function ($app) {
return new ConfigService();
});
}
}
Using Singleton
Retrieve the singleton instance in a controller.
// app/Http/Controllers/SettingsController.php
namespace App\Http\Controllers;
use App\Services\ConfigService;
class SettingsController extends Controller
{
protected $configService;
public function __construct(ConfigService $configService)
{
$this->configService = $configService;
}
public function showSettings()
{
$setting = $this->configService->get('site_name');
return view('settings', compact('setting'));
}
}
Routes
Define a route for the controller action.
// routes/web.php
use App\Http\Controllers\SettingsController;
Route::get('/settings', [SettingsController::class, 'showSettings']);
4. Observer Pattern
The Observer Pattern defines a one-to-many dependency between objects. When one object changes state, all dependent objects are notified and updated automatically.
Observer
Create an observer to handle user creation events.
// app/Observers/UserObserver.php
namespace App\Observers;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeEmail;
class UserObserver
{
public function created(User $user)
{
Mail::to($user->email)->send(new WelcomeEmail($user));
}
}
Register Observer
Register the observer in a service provider.
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Models\User;
use App\Observers\UserObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
User::observe(UserObserver::class);
}
}
5. Factory Pattern
The Factory Pattern provides a way to create objects without specifying the exact class of the object that will be created. Laravel’s model factories are a good example of this pattern.
Factory Definition
Define a factory for creating user instances.
// database/factories/UserFactory.php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'password' => bcrypt('password'),
];
}
}
Using Factory
Generate users in tests or seeders.
// database/seeders/UserSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
class UserSeeder extends Seeder
{
public function run()
{
User::factory()->count(50)->create();
}
}
6. Decorator Pattern
The Decorator Pattern allows behavior to be added to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class.
Base Class
Create a base class for notifications.
// app/Notifications/Notification.php
namespace App\Notifications;
class Notification
{
public function send($message)
{
// Send the notification
}
}
Decorator
Extend the base class to add functionality.
// app/Notifications/EmailNotification.php
namespace App\Notifications;
class EmailNotification extends Notification
{
public function send($message)
{
// Add email-specific logic
parent::send($message);
}
}
Usage
Use the decorator to send notifications.
// app/Http/Controllers/NotificationController.php
namespace App\Http\Controllers;
use App\Notifications\EmailNotification;
class NotificationController extends Controller
{
public function send()
{
$notification = new EmailNotification();
$notification->send('Hello World!');
}
}
Post a Comment