Menu
CoddyTech

Mẫu Adapter

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

Mẫu bộ chuyển đổi là một mẫu thiết kế cấu trúc giúp các giao diện không tương thích có thể hoạt động cùng nhau. Mẫu này đóng vai trò như cầu nối giữa hai lớp, chuyển đổi giao diện của một lớp thành giao diện mà phía máy khách mong đợi. Hãy hình dung mẫu này như một bộ chuyển đổi nguồn, giúp bạn cắm thiết bị châu Âu vào ổ cắm ở Mỹ.

Hãy tưởng tượng bạn có một giao diện MediaPlayer hiện có để phát các tệp âm thanh, nhưng bạn cần tích hợp một thư viện bên thứ ba sử dụng giao diện hoàn toàn khác để phát video:

// Giao diện hiện có mà code của bạn sử dụng
interface MediaPlayer {
    void play(String filename);
}

// Lớp (class) của bên thứ ba có giao diện không tương thích
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

Bộ chuyển đổi bao bọc lớp không tương thích và triển khai giao diện cần thiết, chuyển đổi các lệnh gọi giữa chúng:

class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

Giờ đây, code phía client của bạn có thể dùng trình phát video thông qua giao diện quen thuộc MediaPlayer:

MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Đầu ra: Đang phát video: movie.mp4

Mẫu Adapter rất hữu ích khi tích hợp code cũ hoặc thư viện của bên thứ ba mà không sửa mã nguồn của chúng. Phía máy khách không nhận ra rằng nó đang làm việc với một lớp đã được điều chỉnh. Nó chỉ dùng giao diện mà nó đã biết.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống chuyển đổi nhiệt độ bằng mẫu Adapter nhé! Bạn có một ứng dụng thời tiết hiện có, hoạt động với nhiệt độ Celsius, nhưng cần tích hợp một cảm biến nhiệt độ cũ chỉ cho kết quả theo Fahrenheit. Thay vì sửa đổi một trong hai hệ thống, bạn sẽ tạo một adapter để kết nối chúng.

Bạn sẽ tổ chức code trong bốn tệp:

  • TemperatureProvider.java: Định nghĩa giao diện mà ứng dụng thời tiết cần dùng. Giao diện này cần khai báo phương thức getTemperatureCelsius(), trả về một số thực biểu thị nhiệt độ theo Celsius.
  • FahrenheitSensor.java: Đây là cảm biến cũ có giao diện không tương thích. Hãy tạo một lớp có trường số thực private lưu nhiệt độ theo Fahrenheit, được thiết lập qua hàm khởi tạo. Lớp này cần có phương thức readFahrenheit(), trả về giá trị Fahrenheit đã lưu.
  • SensorAdapter.java: Tạo adapter giúp cảm biến Fahrenheit tương thích với ứng dụng thời tiết. Adapter của bạn cần triển khai TemperatureProvider và bao bọc một FahrenheitSensor. Khi gọi getTemperatureCelsius(), adapter cần đọc giá trị từ cảm biến rồi chuyển đổi sang Celsius theo công thức: (fahrenheit - 32) * 5 / 9.
  • Main.java: Kết hợp mọi thứ! Bạn sẽ nhận một đầu vào: giá trị nhiệt độ theo Fahrenheit (số thực).

    Tạo một FahrenheitSensor với giá trị đầu vào. Sau đó, tạo một SensorAdapter bao bọc cảm biến này. Lưu adapter vào một biến kiểu TemperatureProvider để minh họa rằng ứng dụng thời tiết có thể sử dụng adapter thông qua giao diện cần dùng.

    In kết quả theo định dạng này: Temperature: [celsius] C, trong đó celsius được định dạng với một chữ số thập phân.

Bạn sẽ nhận một đầu vào: nhiệt độ Fahrenheit (số thực).

Ví dụ, với đầu vào 98.6, đầu ra sẽ là:

Temperature: 37.0 C

Hãy chú ý cách lớp Main chỉ làm việc với giao diện TemperatureProvider. Lớp này không biết rằng nhiệt độ thực tế đến từ một cảm biến Fahrenheit được điều chỉnh phía sau. Đây chính là nét tinh tế của mẫu Adapter!

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double fahrenheit = scanner.nextDouble();
        
        // TODO: Tạo FahrenheitSensor với giá trị đầu vào
        
        // TODO: Tạo SensorAdapter bao bọc cảm biến
        
        // TODO: Lưu bộ chuyển đổi vào biến TemperatureProvider
        
        // TODO: Lấy nhiệt độ theo độ C và in ra
        // Định dạng: "Temperature: [celsius] C" với một chữ số thập phân
        // Gợi ý: Dùng String.format("%.1f", value) để định dạng
    }
}
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