Menu
CoddyTech

Mẫu Observer

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 68 trên 87.

Mẫu Observer là một mẫu thiết kế hành vi thiết lập mối quan hệ một nhiều giữa các đối tượng. Khi một đối tượng (đối tượng chủ thể) thay đổi trạng thái, tất cả đối tượng phụ thuộc vào nó (các đối tượng quan sát) sẽ tự động nhận thông báo và cập nhật. Hãy hình dung như đăng ký nhận bản tin: người đăng ký nhận thông tin cập nhật mỗi khi nội dung mới được đăng.

Mẫu này gồm hai thành phần chính: một đối tượng duy trì danh sách các đối tượng quan sát và thông báo cho chúng khi có thay đổi, cùng các đối tượng quan sát định nghĩa phương thức cập nhật để phản hồi thông báo:

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class NewsPublisher {
    private List<Observer> subscribers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        subscribers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        subscribers.remove(observer);
    }
    
    public void publish(String news) {
        for (Observer subscriber : subscribers) {
            subscriber.update(news);
        }
    }
}

class EmailSubscriber implements Observer {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    public void update(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

Khi nhà phát hành đăng tin, tất cả người đăng ký sẽ tự động nhận được thông báo:

NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));

publisher.publish("Breaking news!");
// Đầu ra:
// Email to alice@mail.com: Breaking news!
// Email to bob@mail.com: Breaking news!

Mẫu thiết kế Observer giúp giảm sự phụ thuộc chặt chẽ: đối tượng chủ thể không cần biết các lớp cụ thể của các đối tượng quan sát, mà chỉ cần biết chúng triển khai giao diện Observer. Nhờ vậy, bạn có thể dễ dàng thêm các kiểu đối tượng quan sát mới mà không cần sửa đổi đối tượng chủ thể.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống cảnh báo giá cổ phiếu bằng Mẫu thiết kế Observer! Bạn sẽ tạo một hệ thống trong đó bộ theo dõi cổ phiếu thông báo cho nhiều nhà đầu tư mỗi khi giá cổ phiếu thay đổi, để mỗi nhà đầu tư có thể phản ứng theo cách riêng khi giá cập nhật.

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

  • Observer.java: Định nghĩa giao diện Observer để tất cả nhà đầu tư triển khai. Giao diện cần khai báo một phương thức duy nhất là update(String stockName, double price), cho phép các observer nhận thông báo khi giá thay đổi.
  • StockTicker.java: Tạo lớp chủ thể lưu danh sách observer và thông báo cho họ khi giá thay đổi. StockTicker cần có:

    Một trường String riêng tư lưu tên cổ phiếu, được thiết lập qua hàm khởi tạo.

    Một trường double riêng tư lưu giá hiện tại, ban đầu là 0.

    Một danh sách riêng tư để lưu các observer đã đăng ký.

    Một phương thức subscribe(Observer observer) để thêm observer vào danh sách.

    Một phương thức unsubscribe(Observer observer) để xóa observer khỏi danh sách.

    Một phương thức setPrice(double price) để cập nhật giá, sau đó thông báo cho tất cả observer bằng cách gọi phương thức update của họ với tên cổ phiếu và giá mới.

  • Investors.java: Tạo hai kiểu nhà đầu tư khác nhau triển khai giao diện Observer:

    DayTrader: có một trường name riêng tư được thiết lập qua hàm khởi tạo. Khi nhận cập nhật, in ra [name] received alert: [stockName] is now $[price] - Making quick trade!

    LongTermInvestor: có một trường name riêng tư được thiết lập qua hàm khởi tạo. Khi nhận cập nhật, in ra [name] received alert: [stockName] is now $[price] - Holding steady.

    Định dạng giá với hai chữ số thập phân.

  • Main.java: Kết hợp hệ thống observer của bạn! Bạn sẽ nhận ba đầu vào: tên cổ phiếu (String), lần cập nhật giá thứ nhất (double) và lần cập nhật giá thứ hai (double).

    Tạo một StockTicker với tên cổ phiếu đã cho. Tạo một DayTrader có tên "Alice" và một LongTermInvestor có tên "Bob", rồi đăng ký cả hai với bộ theo dõi.

    Đặt giá thành giá trị đầu vào thứ nhất (tất cả observer đều nhận thông báo). Sau đó hủy đăng ký Alice. Cuối cùng, đặt giá thành giá trị đầu vào thứ hai (lần này chỉ Bob nhận thông báo).

Bạn sẽ nhận ba đầu vào theo thứ tự: tên cổ phiếu (String), giá thứ nhất (double), giá thứ hai (double).

Thử thách này cho thấy sức mạnh của Mẫu thiết kế Observer: StockTicker không cần biết gì về từng kiểu nhà đầu tư cụ thể. Nó chỉ cần biết họ triển khai Observer. Khi bạn hủy đăng ký Alice, cô ấy sẽ ngừng nhận cập nhật, còn Bob vẫn tiếp tục nhận thông báo. Cách ghép nối lỏng lẻo này giúp bạn dễ dàng thêm kiểu nhà đầu tư mới mà không cần thay đổi bộ theo dõi!

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc dữ liệu đầu vào
        String stockName = scanner.nextLine();
        double firstPrice = scanner.nextDouble();
        double secondPrice = scanner.nextDouble();
        
        // TODO: Tạo StockTicker với tên cổ phiếu đã cho
        
        // TODO: Tạo DayTrader có tên "Alice"
        
        // TODO: Tạo LongTermInvestor có tên "Bob"
        
        // TODO: Đăng ký cho cả Alice và Bob theo dõi ticker
        
        // TODO: Đặt giá thành firstPrice (cả hai đối tượng theo dõi đều nhận thông báo)
        
        // TODO: Hủy đăng ký theo dõi cho Alice
        
        // TODO: Đặt giá thành secondPrice (chỉ Bob nhận thông báo)
        
        scanner.close();
    }
}
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