Giới thiệu về Mẫu thiết kế Strategy
Mẫu thiết kế Strategy (Chiến lược) là một trong những mẫu thiết kế hành vi quan trọng trong lập trình, cho phép bạn thay đổi hành vi của một đối tượng tại thời điểm chạy. Mẫu này tách biệt chức năng cốt lõi của đối tượng với các thuật toán cụ thể mà nó sử dụng. Điều này giúp cho việc thay đổi hoặc mở rộng hành vi của đối tượng trở nên linh hoạt hơn.
Các khái niệm cơ bản
- Giao diện Strategy: Đây là giao diện định nghĩa các thao tác chung mà tất cả các thuật toán khác nhau sẽ triển khai. Điều này đảm bảo rằng tất cả các chiến lược có thể hoán đổi cho nhau đều có thể được sử dụng bởi đối tượng ngữ cảnh.
- Các Chiến lược Cụ thể: Là các lớp triển khai các thuật toán cụ thể. Mỗi lớp chiến lược cụ thể sẽ triển khai giao diện chiến lược và cung cấp hành vi riêng cho thao tác đó.
- Đối tượng Ngữ cảnh: Đối tượng này giữ một tham chiếu đến một đối tượng chiến lược và chuyển giao thao tác cụ thể cho nó. Nó có thể thay đổi hành vi của mình tại thời điểm chạy bằng cách chuyển đổi tham chiếu tới một chiến lược cụ thể khác.
Cấu trúc Mẫu thiết kế Strategy trong Rust
Trong Rust, chúng ta có thể triển khai mẫu thiết kế Strategy như sau:
rust
trait TransportationToAirport {
fn going_to_the_airport(&self);
}
struct ByBus {}
impl TransportationToAirport for ByBus {
fn going_to_the_airport(&self) {
println!("Đi đến sân bay bằng xe buýt...");
}
}
struct ByOla {}
impl TransportationToAirport for ByOla {
fn going_to_the_airport(&self) {
println!("Đi đến sân bay bằng Ola...");
}
}
struct ByRapido {}
impl TransportationToAirport for ByRapido {
fn going_to_the_airport(&self) {
println!("Đi đến sân bay bằng Rapido...");
}
}
struct Traveller {
strategy: Box<dyn TransportationToAirport>,
}
impl Traveller {
fn new(strategy: Box<dyn TransportationToAirport>) -> Self {
Traveller { strategy }
}
fn travel(&self) {
self.strategy.going_to_the_airport();
}
pub fn set_strategy(&mut self, strategy: Box<dyn TransportationToAirport>) {
self.strategy = strategy;
}
}
fn main() {
println!("Nhập lựa chọn của bạn...");
let mut choice = String::new();
io::stdin().read_line(&mut choice).expect("Không thể đọc dòng");
if choice.trim().eq_ignore_ascii_case("BUS") {
let traveller = Traveller::new(Box::new(ByBus {}));
traveller.travel();
} else if choice.trim().eq_ignore_ascii_case("OLA") {
let traveller = Traveller::new(Box::new(ByOla {}));
traveller.travel();
} else if choice.trim().eq_ignore_ascii_case("RAPIDO") {
let traveller = Traveller::new(Box::new(ByRapido {}));
traveller.travel();
} else {
println!("Lựa chọn không hợp lệ. Vui lòng chọn BUS, OLA hoặc RAPIDO.");
}
}
Ví dụ thực tế
Khi bạn chạy đoạn mã trên, bạn sẽ thấy lời nhắc nhập lựa chọn. Nếu bạn nhập chọn "OLA", đầu ra sẽ là:
Nhập lựa chọn của bạn...
OLA
Đi đến sân bay bằng Ola...
Các thực tiễn tốt nhất khi sử dụng mẫu thiết kế Strategy
- Tích hợp với Dependency Injection: Sử dụng Dependency Injection giúp bạn dễ dàng thay đổi các chiến lược mà không cần thay đổi mã nguồn chính.
- Mở rộng dễ dàng: Khi cần thêm một phương thức vận chuyển mới, bạn chỉ cần tạo một lớp mới mà không cần thay đổi các lớp hiện có.
- Giảm thiểu mã lặp lại: Mỗi chiến lược cụ thể chỉ cần triển khai một giao diện chung, giúp giảm thiểu mã lặp lại.
Những cạm bẫy thường gặp
- Quá nhiều chiến lược: Đôi khi, việc tạo quá nhiều chiến lược có thể làm cho mã trở nên phức tạp và khó bảo trì. Chỉ nên tạo ra các chiến lược cần thiết cho ứng dụng.
- Mất đi sự rõ ràng: Nếu không tổ chức mã một cách hợp lý, nó có thể trở nên khó đọc và khó hiểu.
Mẹo hiệu suất
- Giảm thiểu việc tạo đối tượng: Nếu bạn có nhiều đối tượng chiến lược giống nhau, hãy xem xét việc sử dụng một đối tượng chung thay vì tạo mới.
- Sử dụng enum: Trong một số trường hợp, việc sử dụng enum thay cho nhiều lớp có thể giúp đơn giản hóa mã và tăng hiệu suất.
Kết luận
Mẫu thiết kế Strategy rất hữu ích trong việc quản lý hành vi của các đối tượng trong ứng dụng Rust của bạn. Bằng cách tách biệt các thuật toán khỏi đối tượng, bạn có thể dễ dàng mở rộng và thay đổi hành vi mà không cần thay đổi mã nguồn chính. Hãy thử triển khai mẫu này trong dự án tiếp theo của bạn và tận hưởng sự linh hoạt mà nó mang lại!
Câu hỏi thường gặp
1. Mẫu thiết kế Strategy có thể được sử dụng trong những ngữ cảnh nào?
Mẫu Strategy rất hữu ích trong các tình huống cần thay đổi hành vi động của đối tượng, chẳng hạn như lựa chọn thuật toán xử lý dữ liệu, phương thức vận chuyển, v.v.
2. Có phải luôn luôn sử dụng mẫu Strategy cho mọi tình huống không?
Không, chỉ nên sử dụng mẫu này khi cần sự linh hoạt trong việc thay đổi hành vi của đối tượng mà không làm phức tạp mã nguồn.
Hãy để lại câu hỏi hoặc ý kiến của bạn ở phần bình luận dưới bài viết này!