Factory Method Design Pattern Explained with PHP Examples

Factory Method là một trong những Creational Design Patterns (mẫu thiết kế khởi tạo), giúp bạn tạo đối tượng mà không cần chỉ định lớp cụ thể. Thay vì khởi tạo đối tượng trực tiếp bằng từ khóa new, Factory Method sử dụng một phương thức được định nghĩa trong một lớp hoặc interface để quyết định lớp nào sẽ được khởi tạo.

[🧑‍💻 Github]

Mục đích

  • Cung cấp sự linh hoạt khi thêm các lớp mới mà không cần thay đổi mã nguồn hiện tại.
  • Tăng khả năng mở rộng (Open/Closed Principle).
  • Tách biệt logic khởi tạo đối tượng ra khỏi logic nghiệp vụ chính

Cấu trúc Factory Method

  1. Product (Sản phẩm): Interface hoặc lớp trừu tượng định nghĩa các đối tượng được tạo.
  2. Concrete Product (Sản phẩm cụ thể): Các lớp cụ thể triển khai hoặc mở rộng từ Product.
  3. Creator (Người tạo): Lớp hoặc interface định nghĩa phương thức factoryMethod trả về Product.
  4. Concrete Creator (Người tạo cụ thể): Lớp cụ thể triển khai phương thức factoryMethod để tạo ra Concrete Product.

Ví dụ minh họa: Factory Method trong PHP

1. Khởi tạo lớp sản phẩm 

<?php
interface Logger {
    public function log(string $message): void;
}

class FileLogger implements Logger {
    public function log(string $message): void {
        echo "Logging to a file: $message";
    }
}

class DatabaseLogger implements Logger {
    public function log(string $message): void {
        echo "Logging to a database: $message";
    }
}
?>

2. Lớp Creator và Concrete Creator

<?php
abstract class LoggerFactory {
    // Phương thức factory method
    abstract public function createLogger(): Logger;

    public function log(string $message): void {
        $logger = $this->createLogger();
        $logger->log($message);
    }
}

class FileLoggerFactory extends LoggerFactory {
    public function createLogger(): Logger {
        return new FileLogger();
    }
}

class DatabaseLoggerFactory extends LoggerFactory {
    public function createLogger(): Logger {
        return new DatabaseLogger();
    }
}
?>

3. Sử dụng Factory Method

<?php
// Tạo logger dạng File
$fileLoggerFactory = new FileLoggerFactory();
$fileLoggerFactory->log("This is a file log message.");

// Tạo logger dạng Database
$databaseLoggerFactory = new DatabaseLoggerFactory();
$databaseLoggerFactory->log("This is a database log message.");
?>

Ưu điểm của Factory Method

  1. Dễ mở rộng: Thêm loại sản phẩm mới chỉ cần tạo một lớp sản phẩm và một lớp creator tương ứng.
  2. Tái sử dụng: Cùng một logic nghiệp vụ, nhưng các đối tượng khác nhau có thể được tạo ra mà không sửa đổi mã nguồn chính.
  3. Tách biệt trách nhiệm: Creator chịu trách nhiệm khởi tạo đối tượng, logic khởi tạo không nằm trong logic nghiệp vụ.

Nhược điểm

  • Code phức tạp hơn vì cần thêm các lớp Creator và Concrete Product.
  • Khả năng mở rộng đòi hỏi thiết kế ban đầu phải chuẩn xác.

Factory Method phù hợp trong các trường hợp cần khởi tạo nhiều loại đối tượng khác nhau nhưng muốn giấu đi sự phức tạp của việc tạo đối tượng cụ thể.

Dưới đây là ví dụ về việc sử dụng Factory Method để tạo CRUD cho UserRole trong PHP. Mỗi loại (User và Role) sẽ được quản lý thông qua một Factory riêng, giúp code linh hoạt và dễ mở rộng 

Example 2: 

1. Định nghĩa Interface chung

<?php
interface CrudInterface {
    public function create(array $data): void;
    public function read(int $id): ?array;
    public function update(int $id, array $data): void;
    public function delete(int $id): void;
}
?>

2. Tạo lớp Product (User và Role)

<?php
class User implements CrudInterface {
    private $users = []; // Mô phỏng cơ sở dữ liệu

    public function create(array $data): void {
        $this->users[$data['id']] = $data;
        echo "User created: " . json_encode($data) . PHP_EOL;
    }

    public function read(int $id): ?array {
        return $this->users[$id] ?? null;
    }

    public function update(int $id, array $data): void {
        if (isset($this->users[$id])) {
            $this->users[$id] = array_merge($this->users[$id], $data);
            echo "User updated: " . json_encode($this->users[$id]) . PHP_EOL;
        } else {
            echo "User not found." . PHP_EOL;
        }
    }

    public function delete(int $id): void {
        unset($this->users[$id]);
        echo "User deleted: $id" . PHP_EOL;
    }
}

class Role implements CrudInterface {
    private $roles = []; // Mô phỏng cơ sở dữ liệu

    public function create(array $data): void {
        $this->roles[$data['id']] = $data;
        echo "Role created: " . json_encode($data) . PHP_EOL;
    }

    public function read(int $id): ?array {
        return $this->roles[$id] ?? null;
    }

    public function update(int $id, array $data): void {
        if (isset($this->roles[$id])) {
            $this->roles[$id] = array_merge($this->roles[$id], $data);
            echo "Role updated: " . json_encode($this->roles[$id]) . PHP_EOL;
        } else {
            echo "Role not found." . PHP_EOL;
        }
    }

    public function delete(int $id): void {
        unset($this->roles[$id]);
        echo "Role deleted: $id" . PHP_EOL;
    }
}
?>

3. Tạo lớp Factory

<?php
abstract class CrudFactory {
    abstract public function createCrud(): CrudInterface;
}

class UserFactory extends CrudFactory {
    public function createCrud(): CrudInterface {
        return new User();
    }
}

class RoleFactory extends CrudFactory {
    public function createCrud(): CrudInterface {
        return new Role();
    }
}
?>

4. Sử dụng Factory Method cho CRUD

<?php
// Factory cho User
$userFactory = new UserFactory();
$userCrud = $userFactory->createCrud();

// Thực hiện các thao tác CRUD cho User
$userCrud->create(['id' => 1, 'name' => 'Hoa Dev', 'email' => 'hoadev@example.com']);
$userCrud->update(1, ['email' => 'hoadev.code@example.com']);
$userData = $userCrud->read(1);
echo "Read User: " . json_encode($userData) . PHP_EOL;
$userCrud->delete(1);

// Factory cho Role
$roleFactory = new RoleFactory();
$roleCrud = $roleFactory->createCrud();

// Thực hiện các thao tác CRUD cho Role
$roleCrud->create(['id' => 101, 'name' => 'Admin']);
$roleCrud->update(101, ['name' => 'Super Admin']);
$roleData = $roleCrud->read(101);
echo "Read Role: " . json_encode($roleData) . PHP_EOL;
$roleCrud->delete(101);
?>

Kết quả

Khi chạy đoạn code trên, kết quả sẽ hiển thị như sau:

User created: {"id":1,"name":"Hoa Dev","email":"hoadev@example.com"}
User updated: {"id":1,"name":"Hoa Dev","email":"hoadev.code@example.com"}
Read User: {"id":1,"name":"Hoa Dev","email":"hoadev.code@example.com"}
User deleted: 1
Role created: {"id":101,"name":"Admin"}
Role updated: {"id":101,"name":"Super Admin"}
Read Role: {"id":101,"name":"Super Admin"}
Role deleted: 101

Ưu điểm

  1. Tách biệt logic CRUD: Mỗi Factory chịu trách nhiệm tạo ra một loại đối tượng cụ thể (User hoặc Role).
  2. Dễ mở rộng: Có thể dễ dàng thêm các thực thể mới (ví dụ: Permission) bằng cách tạo lớp Product và Factory tương ứng.
  3. Tăng tính tái sử dụng: Logic CRUD chung được định nghĩa trong interface, đảm bảo mọi đối tượng tuân theo một chuẩn.

Bạn có thể áp dụng mô hình này để quản lý nhiều loại đối tượng khác nhau trong ứng dụng của mình.

Bài Viết Liên Quan

x

Xin chào! Hãy ủng hộ chúng tôi bằng cách nhấp vào quảng cáo trên trang web. Việc này giúp chúng tôi có kinh phí để duy trì và phát triển website ngày một tốt hơn. (Hello! Please support us by clicking on the ads on this site. Your clicks provide us with the funds needed to maintain and improve the website continuously.)

Ngoài ra, hãy đăng ký kênh YouTube của chúng tôi để không bỏ lỡ những nội dung hữu ích! (Also, subscribe to our YouTube channel to stay updated with valuable content!)

Đăng Ký