Menu
CoddyTech

Mẫu Singleton

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

Mẫu Singleton đảm bảo một lớp chỉ có một đối tượng duy nhất trong toàn bộ ứng dụng và cung cấp một điểm truy cập toàn cục đến đối tượng đó. Mẫu này hữu ích khi cần đúng một đối tượng để điều phối các hoạt động trong hệ thống, chẳng hạn như trình quản lý cấu hình, kết nối cơ sở dữ liệu hoặc dịch vụ ghi nhật ký.

Trong Dart, bạn có thể triển khai Singleton bằng cách kết hợp hàm khởi tạo factory với một instance tĩnh riêng tư:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Hàm khởi tạo (constructor) có tên riêng, chỉ dùng trong lớp
  AppConfig._internal();
  
  // Hàm khởi tạo factory trả về cùng một instance
  factory AppConfig() {
    return _instance;
  }
}

void main() {
  var config1 = AppConfig();
  var config2 = AppConfig();
  
  config1.appName = 'UpdatedApp';
  
  print(config2.appName);  // UpdatedApp
  print(identical(config1, config2));  // true
}

Hàm khởi tạo riêng tư (constructor) _internal() ngăn việc tạo instance từ bên ngoài. Thuộc tính tĩnh _instance lưu instance duy nhất, được tạo một lần khi lớp được tải. Mỗi lần gọi AppConfig() đều trả về cùng instance này, vì vậy những thay đổi qua một tham chiếu sẽ hiển thị ở mọi nơi.

Hãy dùng Singleton một cách hạn chế, vì chúng tạo ra trạng thái toàn cục, khiến việc kiểm thử khó hơn. Chúng phù hợp nhất với các tài nguyên dùng chung thực sự cần có trạng thái nhất quán trong toàn bộ ứng dụng.

challenge icon

Thử thách

Dễ

Hãy xây dựng một trình quản lý cài đặt trò chơi bằng mẫu Singleton! Bạn sẽ tạo một hệ thống đảm bảo chỉ có một đối tượng của cài đặt trò chơi tồn tại trong toàn bộ ứng dụng, để mọi phần trong trò chơi đều dùng chung một cấu hình.

Bạn sẽ sắp xếp code thành hai tệp:

  • game_settings.dart: Tạo lớp GameSettings triển khai mẫu Singleton. Trình quản lý cài đặt cần có:
    • Một đối tượng riêng tư, static và final, lưu giữ đối tượng GameSettings duy nhất
    • Một hàm khởi tạo có tên riêng tư để ngăn việc khởi tạo từ bên ngoài
    • Một hàm khởi tạo factory luôn trả về cùng một đối tượng
    • Ba trường cài đặt: difficulty (String, mặc định: "Normal"), soundEnabled (bool, mặc định: true) và playerName (String, mặc định: "Player1")
    • Một phương thức displaySettings() in ra cài đặt hiện tại theo định dạng này: Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off] (in ra "on" nếu soundEnabled là true, "off" nếu là false)
  • main.dart: Nhập cài đặt trò chơi và minh họa Singleton hoạt động chính xác:
    • Lấy đối tượng cài đặt và đặt tên là settings1
    • Gọi displaySettings() để hiển thị các giá trị mặc định
    • Thay đổi cài đặt: đổi playerName thành "Hero", difficulty thành "Hard" và soundEnabled thành false
    • Lấy một tham chiếu khác đến cài đặt và đặt tên là settings2
    • Gọi displaySettings() trên settings2 để chứng minh rằng nó phản ánh những thay đổi được thực hiện thông qua settings1
    • In ra việc settings1 và settings2 có giống hệt nhau hay không theo định dạng: Same instance: [true/false]

Điều này minh họa lợi ích cốt lõi của Singleton: các thay đổi được thực hiện ở bất kỳ đâu trong ứng dụng đều hiển thị ngay ở mọi nơi khác, vì chỉ có một đối tượng duy nhất!

Đầu ra mong đợi:

Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true

Tự làm thử

import 'game_settings.dart';

void main() {
  // TODO: Lấy instance cài đặt và đặt tên là settings1
  
  // TODO: Gọi displaySettings() để hiển thị các giá trị mặc định
  
  // TODO: Thay đổi các cài đặt:
  // - Đổi playerName thành "Hero"
  // - Đổi difficulty thành "Hard"
  // - Đổi soundEnabled thành false
  
  // TODO: Lấy một tham chiếu khác đến cài đặt và đặt tên là settings2
  
  // TODO: Gọi displaySettings() trên settings2 để chứng minh nó phản ánh các thay đổi
  
  // TODO: In ra liệu settings1 và settings2 có phải cùng một instance không
  // Định dạng: Same instance: [true/false]
}
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 Dart online