Featured image of post Design Patern - Factory Pattern và cách apply Factory Pattern vào dự án eCommerce để xử lý các phương thức thanh toán khác nhau

Design Patern - Factory Pattern và cách apply Factory Pattern vào dự án eCommerce để xử lý các phương thức thanh toán khác nhau

Bài trước chúng ta đã nói về Strategy Pattern và các áp dụng Strategy để apply discount voucher một cách linh hoạt. Trong bài này, chúng ta sẽ cùng nhau tìm hiểu về Factory Pattern và cách mà mình apply Factory Pattern xử lý các phươnng thức thanh toán khác nhau từ phía Client

Giới thiệu về Factory Pattern

Factory Pattern là một trong những mẫu thiết kế phổ biến nhất trong Design Patern. Vì tính đa dụng trong hầu hết các business case thực tế nên gần như tất cả các dự án về tech mình làm đều sử dụng mẫu này(có thể code implement khác nhưng ý tưởng sẽ giống).

Nó thuộc nhóm các mẫu khởi tạo (Creational Patterns), tập trung vào việc tạo ra các instance trong hệ thống.

Ý tưởng cốt lõi của Factory Pattern là định nghĩa một interface chung để tạo ra class implement interface đó, giúp cho chúng có thể implement những method chung đã được định nghĩa sẵn trong interface ban đầu . Điều này giúp tạo ra các instance mà không cần phải chỉ rõ class cụ thể của instance sẽ được tạo - nhờ vào tính đa hình trong OOP, giúp giảm sự phụ thuộc chặt chẽ trong code.

Khi nào nên sử dụng Factory Pattern

Factory Pattern đặc biệt hữu ích trong các tình huống sau:

  • Khi việc tạo instance phức tạp: Khi việc tạo instance liên quan đến các quy trình phức tạp như thiết lập nhiều tham số, sử dụng các dependencies, hoặc thực hiện khởi tạo theo nhiều bước.
  • Khi cần kiểm soát việc tạo instance: Nếu bạn cần kiểm soát cách thức và thời điểm một instance được tạo ra, đặc biệt khi làm việc với các loại instance cụ thể cần tuân theo các quy tắc hoặc hướng dẫn nhất định.
  • Khi các class cần có chung một interface: Khi làm việc với nhiều class implement cùng một interface hoặc kế thừa từ một class cơ sở chung, và bạn muốn đóng gói logic khởi tạo cho các class này.
  • Để tăng cường tính linh hoạt: Nếu bạn muốn giảm sự phụ thuộc của code logic vào các class cụ thể đang được khởi tạo, Factory Pattern giúp abstract quá trình khởi tạo, làm cho code linh hoạt và dễ bảo trì hơn.

Sử dụng Factory Pattern để xử lý các phương thức thanh toán từ Client

Mình và team đã phát triển một eCommerce system và cần tạo ra các phương thức thanh toán khác nhau như Thẻ Tín Dụng, COD(Cash On Delivery), và Chuyển Khoản Ngân Hàng. Mỗi phương thức thanh toán có chi tiết triển khai khác nhau, nhưng chúng đều chia sẻ một interface chung, chẳng hạn như PaymentMethod.

Bây giờ, chúng ta cần define một interface chung cho tất cả các phương thức thanh toán:

1
2
3
public interface PaymentMethod {
    void processPayment(double amount);
}

Tiếp theo, tạo các class implemment cụ thể cho từng loại phương thức thanh toán:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CreditCardPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // Triển khai xử lý thanh toán bằng Thẻ Tín Dụng
        System.out.println("Xử lý thanh toán bằng Thẻ Tín Dụng số tiền " + amount);
    }
}

public class CashOnDelivery implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // Triển khai xử lý thanh toán bằng COD
        System.out.println("Xử lý thanh toán bằng COD số tiền " + amount);
    }
}

public class BankTransferPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // Triển khai xử lý thanh toán bằng Chuyển Khoản Ngân Hàng
        System.out.println("Xử lý thanh toán bằng Chuyển Khoản Ngân Hàng số tiền " + amount);
    }
}

Sau đó, cần có một class với một static method đóng vai như là một Factory để tạo ra phương thức thanh toán compatible với input từ phía Client

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class PaymentMethodFactory {
    public static PaymentMethod createPaymentMethod(String userInputType) {
        switch (userInputType) {
            case "CreditCard":
                return new CreditCardPayment();
            case "COD":
                return new CashOnDelivery();
            case "BankTransfer":
                return new BankTransferPayment();
            default:
                throw new IllegalArgumentException("Loại phương thức thanh toán không xác định");
        }
    }
}

Cuối cùng, chỉ cần gọi Static factory method để tạo ra payment method compatible với userInput

1
2
3
4
5
6
7
public class ECommercePlatform {
    public static void main(String[] args) {
        String userInputType = "CreditCard"; // should be ENUM, but i will use string for demonstrating 
        PaymentMethod payment = PaymentMethodFactory.createPaymentMethod(userInputType);
        payment.processPayment(150.00);
    }
}

Như vậy là đã xong, chúng ta đã xử lý xong việc khởi tạo phương thức thanh toán hợp lý mà không phải dùng các method quá lớn cũng như code change nhiều, sau này khi có method mới chỉ cần thêm vào static factory createPaymentMethod là done. Quá tiện phải không nào?

Tổng kết

Factory Pattern là một mẫu thiết kế giúp quản lý và tổ chức việc tạo instance hợp lý dựa vào business case của bạn. Nó trừu tượng hóa quá trình khởi tạo và cung cấp tính linh hoạt trong việc chọn loại đối tượng phù hợp tại thời điểm chạy, giúp tăng tính linh hoạt và bảo trì codebase. Bằng cách triển khai Factory Pattern, bạn có thể làm cho ứng dụng của mình dễ scale, dễ bảo trì hơn, và thích nghi với các thay đổi, đặc biệt trong các hệ thống phức tạp nơi nhiều loại đối tượng tham gia.

Hy vọng qua bài này mình đã giúp các bạn có thể hiểu rõ hơn về Factory Pattern và ứng dụng của nó, cũng như cách cài đặt một Factory đơn giản để xử lý việc khởi tạo các instance phù hợp!

HAPPY CODING!

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy