Mẫu Observer
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 92 trên 110.
Mẫu thiết kế Observer 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ả các đối tượng phụ thuộc vào nó (đối tượng quan sát) sẽ tự động nhận được thông báo. Mẫu này rất phù hợp với các tình huống như cập nhật giao diện người dùng, hệ thống sự kiện hoặc bất kỳ tình huống nào mà nhiều phần trong ứng dụng cần phản ứng với các thay đổi.
Mẫu này có hai vai trò chính: Chủ thể duy trì danh sách các trình quan sát và thông báo cho họ khi có thay đổi, còn Trình quan sát tự đăng ký và phản hồi các cập nhật:
abstract class Observer {
void update(String message);
}
class NewsAgency {
final List<Observer> _observers = [];
String _latestNews = '';
void subscribe(Observer observer) {
_observers.add(observer);
}
void unsubscribe(Observer observer) {
_observers.remove(observer);
}
void publishNews(String news) {
_latestNews = news;
for (var observer in _observers) {
observer.update(_latestNews);
}
}
}
class NewsChannel implements Observer {
final String name;
NewsChannel(this.name);
@override
void update(String message) {
print('$name received: $message');
}
}
void main() {
var agency = NewsAgency();
var cnn = NewsChannel('CNN');
var bbc = NewsChannel('BBC');
agency.subscribe(cnn);
agency.subscribe(bbc);
agency.publishNews('Breaking news!');
// CNN đã nhận: Tin nóng!
// BBC đã nhận: Tin nóng!
}Khi gọi publishNews, cơ quan lần lượt duyệt qua tất cả các observer đã đăng ký và gọi phương thức update của họ. Observer có thể đăng ký hoặc hủy đăng ký bất cứ lúc nào, giúp hệ thống linh hoạt và ít phụ thuộc lẫn nhau: đối tượng chủ thể không cần biết kiểu cụ thể của các observer.
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 Observer! Bạn sẽ tạo một hệ thống trong đó mã theo dõi cổ phiếu thông báo cho nhiều nhà đầu tư mỗi khi giá thay đổi, để mỗi nhà đầu tư có thể phản ứng theo cách riêng trước những cập nhật của thị trường.
Bạn sẽ sắp xếp code thành hai tệp:
stock_system.dart: Tạo hệ thống observer tại đây:- Một lớp trừu tượng
Investorcó phương thứcvoid onPriceChange(String stockName, double price) - Một lớp
DayTradertriển khaiInvestor. Lớp này có trườngnamevà phương thứconPriceChangein ra:[name] sees [stockName] at $[price] - Making quick trade! - Một lớp
LongTermInvestortriển khaiInvestor. Lớp này có trườngnamevà phương thứconPriceChangein ra:[name] notes [stockName] at $[price] - Holding steady. - Một lớp
StockTicker(đối tượng phát thông báo) có:- Một trường
String stockName - Một danh sách riêng để lưu các nhà đầu tư đã đăng ký
- Một phương thức
subscribe(Investor investor)để thêm nhà đầu tư - Một phương thức
unsubscribe(Investor investor)để xóa nhà đầu tư - Một phương thức
updatePrice(double newPrice)thông báo giá mới cho tất cả nhà đầu tư đã đăng ký
- Một trường
- Một lớp trừu tượng
main.dart: Nhập hệ thống cổ phiếu của bạn và minh họa cách mẫu Observer hoạt động:- Tạo một
StockTickercho cổ phiếu có tênDART - Tạo một
DayTradertênAlicevà mộtLongTermInvestortênBob - Đăng ký cả hai nhà đầu tư với mã theo dõi
- Cập nhật giá thành
150.50(cả hai nhà đầu tư đều nhận được thông báo) - In ra một dòng trống
- Hủy đăng ký Alice khỏi mã theo dõi
- Cập nhật giá thành
155.75(lúc này chỉ Bob nhận được thông báo)
- Tạo một
Ví dụ này cho thấy mẫu Observer tạo ra một hệ thống ít phụ thuộc lẫn nhau. StockTicker không cần biết mình đang thông báo cho nhà giao dịch trong ngày hay nhà đầu tư dài hạn, mà chỉ cần gọi onPriceChange cho những người đã đăng ký!
Đầu ra dự kiến:
Alice sees DART at $150.5 - Making quick trade!
Bob notes DART at $150.5 - Holding steady.
Bob notes DART at $155.75 - Holding steady.Tự làm thử
import 'stock_system.dart';
void main() {
// TODO: Tạo một StockTicker cho cổ phiếu tên 'DART'
// TODO: Tạo một DayTrader tên 'Alice'
// TODO: Tạo một LongTermInvestor tên 'Bob'
// TODO: Đăng ký cả hai nhà đầu tư theo dõi ticker
// TODO: Cập nhật giá thành 150.50 (cả hai nhà đầu tư đều phải nhận thông báo)
// TODO: In ra một dòng trống
// TODO: Hủy đăng ký theo dõi ticker cho Alice
// TODO: Cập nhật giá thành 155.75 (giờ chỉ Bob nhận thông báo)
}
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
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiThư viện và câu lệnh importGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcBiến thể hiệnKiến thức cơ bản về hàm khởi tạoÔn tập: Máy tính đơn giản4An toàn với giá trị null
Giới thiệu về an toàn với giá trị nullCó thể null và không thể nullToán tử ? và !Từ khóa late và an toàn với giá trị nullToán tử xử lý nullAn toàn với giá trị null trong lớpÔn tập: hệ thống hồ sơ người dùng7Lớp trừu tượng và interface
Lớp trừu tượngPhương thức trừu tượngInterface trong DartInterface ngầm địnhTriển khai và kế thừaNhiều interfaceÔn tập: Máy tính hình10Bộ sưu tập và kiểu tổng quát
Tổng quan về List, Set và MapBộ sưu tập an toàn về kiểuLớp tổng quátPhương thức tổng quátRàng buộc kiểu tổng quátIterable và IteratorÔn tập: Lưu trữ tổng quát2Hàm khởi tạo trong Dart
Hàm khởi tạo mặc địnhHàm khởi tạo có tênDanh sách khởi tạoHàm khởi tạo hằng sốHàm khởi tạo nhà máyHàm khởi tạo chuyển hướngÔn tập: Trình tạo hình dạng5Đóng gói
Thành viên công khai và riêng tưQuy ước tiền tố _Tính riêng tư ở cấp thư việnTìm hiểu sâu về getter và setterChe giấu thông tinÔn tập: hồ sơ học sinh8Mixin
Giới thiệu về MixinTạo MixinSử dụng nhiều MixinTừ khóa on trong MixinMixin và kế thừaMixin và giao diệnÔn tập: hệ thống động vật3Thuộc tính của lớp
Thành viên instance và thành viên tĩnhTrường final và constBiến latePhương thức và trường tĩnhGetter và setterÔn tập: trình quản lý tài khoản ngân hàng6Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChú thích @overrideTừ khóa lớp finalHàm khởi tạo và kế thừaÔn tập: phân cấp nhân viên9Đa hình
Khái niệm cơ bản về đa hìnhĐa hình qua giao diệnKiểm tra kiểu lúc chạyToán tử is và asTừ khóa hiệp biếnÔn tập: Bộ xử lý thanh toánTự luyện tập: Trình biên dịch Dart online