Trong bài viết trước, Stringee và các bạn đã cùng tìm hiểu về Singleton pattern trong Java. Trong bài viết, chúng ta sẽ cùng tìm hiểu về một Creational Design Pattern khác, đó là Factory pattern trong Java nhé.

1. Factory Pattern trong Java là gì

Factory Method là một creational design pattern cung cấp các interface sử dụng cho việc khởi tạo một đối tượng từ các lớp cha của nó. Nhiệm vụ của Factory pattern là quản lý và khởi tạo các đối tượng theo yêu cầu, điều này giúp cho việc khởi tạo đối tượng trở nên linh hoạt hơn.

Factory pattern đúng như cái tên của nó, đây như là một nhà máy sẽ giúp chúng ta khởi tạo ra các đối tượng. Ở đây, chúng ta sẽ khởi tạo ra đối tượng mà không để lộ logic tạo đối tượng ở phía các người dùng, chúng ta sẽ phải tham chiếu tới đối tượng bằng các interface chung.

Chúng ta nên sử dụng Factory method khi có một class cha(super class) có nhiều class con(sub class) hoặc có nhiều implementation.

2. Cài đặt Factory Pattern trong Java

Một Factory Pattern bao gồm các thành phần cơ bản sau:

  • Super Class: một superclass trong Factory Pattern có thể là một interface, abstract class hay một class thông thường.
  • Sub Classes: các subclass sẽ implement các phương thức của superclass theo nghiệp vụ riêng của nó.
  • Factory Class: một class chịu trách nhiệm khởi tạo các đối tượng subclass dựa theo tham số đầu vào.

Lưu ý: lớp này là Singleton hoặc cung cấp một public static method cho việc truy xuất và khởi tạo đối tượng. Ở đây, Factory method có thể sử dụng if-else hoặc switch-case để xác định class con đầu ra

Chúng ta sẽ đi vào ví dụ tạo Session để truy cập vào các Database. Như các bạn đã biết, các database đều cung cấp một Interface riêng để các client có thể kết nối và thực hiện thao tác với dữ liệu chứa trong đó. Để kết nối vào một database, việc của chúng ta là phải thực hiện tạo kết nối tới db đó bằng đúng cách mà nó cung cấp cho chúng ta. Tại thời điểm hiện tại, giả sử như một công ty nọ có sử dụng hai DB Engine là MySQLPostgreSQL. Tuy nhiên, để dễ dàng cho việc mở rộng hệ thống sau này, khi thiết kế lớp service kết nối tới DB, ta đặt ra vấn đề thiết kế làm sao để có thể cung cấp phương thức linh hoạt cho nhiều DB khác. Từ đây, chúng ta nhận ra rằng, bài toán này hoàn toàn có thể được giải quyết với Factory design pattern.

Cấu trúc của pattern triển khai tại đây sẽ được minh họa như sau:

Và đây là chương trình đã được triển khai:

Supper Class:

public interface Session {

    String getName();

}

Sub Class:

public class MysqlSession implements Session {

    @Override
    public String getName() {
        return "Session used for MySql";
    }

}
public class PostgresqlSession implements Session {

    @Override
    public String getName() {
        return "Session used for PostgresSQL";
    }

}

DbEngine Type:

public enum DbType {

    MYSQL,
    POSTGRESSQL,
    ;

}

Factory Class:

public class SessionFactory {

    private SessionFactory() {
    }

    public Session getSession(DbType dbType) {
        switch (dbType) {
            case MYSQL:
                return new MysqlSession();
            case POSTGRESSQL:
                return new PostgresqlSession();
            default:
                throw new IllegalArgumentException("DbEngine " + dbType + " is not supported!");
        }
    }

    public static SessionFactory getInstance() {
        return Singleton.INSTANCE;
    }

    private static class Singleton {
        public static final SessionFactory INSTANCE = new SessionFactory();
    }

}

Client:

public class Client {

    public static void main(String[] args) {
    
        Session mySqlSession = SessionFactory.getInstance().getSession(DbType.MYSQL);
        System.out.println(mySqlSession.getName());
        
    }

}

Từ ví dụ trên, chúng ta có thể thấy client chỉ gần gọi đến phương thức SessionFactory.getSession() để có thể lấy được session phù hợp với DbEngine mình cần sử dụng.

Khi muốn cung cấp thêm dịch vụ cho các DbEngine khác, chúng ta cần tạo thêm một implementation của Session, tạo thêm một Enumeration cho nó và đăng ký vào logic khởi tạo của Factory class. Từ đó, ta có thể mở rộng ra thêm nhiều DB khác nữa.

3. Lợi ích của việc sử dụng Factory pattern trong Java

  • Factory pattern giúp giảm sự phụ thuộc giữa các module (loose coupling): tại đây, chương trình sẽ tiếp cận với các dịch vụ bằng các Interface thay vì các implementation cụ thể. Từ đó, phía client sẽ không bị ảnh hưởng khi logic của các class Factory hay SubClass của nó bị thay đổi. Sử dụng Factory Pattern là một cách để có thể đạt được principle D(dependency injection) trong bộ quy tắc SOLID.
  • Mở rộng code dễ dàng hơn: khi cần mở rộng, chỉ việc tạo ra sub class và implement thêm vào factory method.
  • Khởi tạo các object nhưng che dấu được logic khởi tạo bên dưới của các sub class.
  • Dễ dạng quản lý life cycle của các Object được tạo bởi Factory Pattern.
  • Thống nhất về naming convention: giúp cho các developer có thể hiểu về cấu trúc source code.

Kết bài

Qua bài biết này, Stringee và các bạn đã cùng tìm hiểu về Factory pattern trong Java. Hi vọng bài viết này sẽ giúp đỡ các bạn nhiều trong quá trình phát triển phần mềm của mình và chú ý theo dõi các bài tiết tới đây của chúng tôi nhé.

Stringee API cung cấp các tính năng như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài chăm sóc khách hàng (CSKH) có thể được nhúng trực tiếp vào các ứng dụng/website của doanh nghiệp nhanh chóng. Điều này giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp, trong khi nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.

Mời quý bạn đọc đăng ký dùng thử và nhận tư vấn tại đây: