Menu
CoddyTech

Mẫu Factory

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 66 trên 87.

Factory Pattern là một mẫu thiết kế khởi tạo, giao việc tạo đối tượng cho một phương thức hoặc lớp riêng. Thay vì dùng trực tiếp new trong code, bạn yêu cầu một factory tạo đối tượng cho mình. Cách này đặc biệt hữu ích khi bạn có nhiều lớp liên quan cùng dùng chung một giao diện hoặc lớp cha.

Hãy xem xét một hệ thống thông báo có thể gửi email, SMS hoặc thông báo đẩy. Nếu không có factory, code của bạn cần biết mọi lớp cụ thể:

// Không dùng Factory, client phải biết tất cả các lớp (class) cụ thể
Notification notification;
if (type.equals("email")) {
    notification = new EmailNotification();
} else if (type.equals("sms")) {
    notification = new SMSNotification();
}

Với mẫu Factory, bạn tập trung logic tạo đối tượng tại một nơi:

public interface Notification {
    void send(String message);
}

public class EmailNotification implements Notification {
    public void send(String message) {
        System.out.println("Email: " + message);
    }
}

public class SMSNotification implements Notification {
    public void send(String message) {
        System.out.println("SMS: " + message);
    }
}

public class NotificationFactory {
    public static Notification create(String type) {
        if (type.equals("email")) {
            return new EmailNotification();
        } else if (type.equals("sms")) {
            return new SMSNotification();
        }
        return null;
    }
}

Giờ đây, code phía client gọn hơn và không phụ thuộc vào các lớp cụ thể:

Notification notification = NotificationFactory.create("email");
notification.send("Hello!");  // Đầu ra: Email: Hello!

Lợi ích chính là bạn chỉ cần cập nhật factory khi thêm loại thông báo mới, còn code phía client vẫn giữ nguyên. Cách này tuân theo nguyên tắc lập trình hướng đến interface, giúp hệ thống linh hoạt hơn và dễ mở rộng hơn.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống vẽ hình bằng mẫu Factory! Thay vì tạo trực tiếp các đối tượng hình trong toàn bộ code, bạn sẽ tập trung logic tạo đối tượng vào một factory, nơi tạo ra nhiều loại hình khác nhau dựa trên một định danh chuỗi đơn giản.

Bạn sẽ sắp xếp code trong bốn tệp:

  • Shape.java: Định nghĩa một giao diện có tên Shape, làm hợp đồng chung cho mọi hình. Giao diện của bạn cần khai báo một phương thức duy nhất là draw(), phương thức này không trả về giá trị mà in thông tin về hình đang được vẽ.
  • Shapes.java: Tạo ba lớp triển khai giao diện Shape:

    Circle - phương thức draw() cần in Drawing a Circle

    Rectangle - phương thức draw() cần in Drawing a Rectangle

    Triangle - phương thức draw() cần in Drawing a Triangle

  • ShapeFactory.java: Tạo lớp factory xử lý việc tạo hình. ShapeFactory cần có phương thức tĩnh createShape(String type) trả về một Shape. Dựa trên tham số type:
    • Nếu type bằng "circle", trả về một Circle mới
    • Nếu type bằng "rectangle", trả về một Rectangle mới
    • Nếu type bằng "triangle", trả về một Triangle mới
    • Với mọi giá trị khác, trả về null
  • Main.java: Kết hợp hệ thống factory của bạn! Bạn sẽ nhận hai đầu vào: hai loại hình (đều là String).

    Với mỗi đầu vào, dùng ShapeFactory để tạo hình và lưu hình đó vào một biến Shape. Nếu factory trả về một hình hợp lệ (không phải null), hãy gọi phương thức draw() của hình đó. Nếu factory trả về null, hãy in Unknown shape: [type], trong đó [type] là đầu vào đã nhận.

    Xử lý lần lượt cả hai đầu vào, mỗi đầu vào tạo một dòng đầu ra riêng.

Bạn sẽ nhận hai đầu vào theo thứ tự: loại hình thứ nhất (String) và loại hình thứ hai (String).

Lưu ý rằng lớp Main của bạn không bao giờ dùng trực tiếp new Circle() hoặc new Rectangle(). Lớp này chỉ biết giao diện Shape và yêu cầu factory tạo các đối tượng. Đó chính là sức mạnh của mẫu Factory: code phía client không phụ thuộc vào các lớp cụ thể!

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc hai loại hình
        String type1 = scanner.nextLine();
        String type2 = scanner.nextLine();
        
        // TODO: Dùng ShapeFactory để tạo hình thứ nhất
        // Nếu hình không phải null, gọi draw()
        // Nếu hình là null, in ra "Unknown shape: [type]"
        
        // TODO: Làm tương tự với hình thứ hai
        
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online