Strategy es un patrón de diseño de comportamiento que convierte un grupo de comportamientos en objetos y los hace intercambiables dentro del objeto de contexto original.
El objeto original, llamado contexto, contiene una referencia a un objeto de estrategia y le delega la ejecución del comportamiento. Para cambiar la forma en que el contexto realiza su trabajo, otros objetos pueden sustituir el objeto de estrategia actualmente vinculado, por otro.
Conceptual Example
A conceptual Strategy example via traits.
conceptual.rs
/// Defines an injectable strategy for building routes.
trait RouteStrategy {
fn build_route(&self, from: &str, to: &str);
}
struct WalkingStrategy;
impl RouteStrategy for WalkingStrategy {
fn build_route(&self, from: &str, to: &str) {
println!("Walking route from {} to {}: 4 km, 30 min", from, to);
}
}
struct PublicTransportStrategy;
impl RouteStrategy for PublicTransportStrategy {
fn build_route(&self, from: &str, to: &str) {
println!(
"Public transport route from {} to {}: 3 km, 5 min",
from, to
);
}
}
struct Navigator<T: RouteStrategy> {
route_strategy: T,
}
impl<T: RouteStrategy> Navigator<T> {
pub fn new(route_strategy: T) -> Self {
Self { route_strategy }
}
pub fn route(&self, from: &str, to: &str) {
self.route_strategy.build_route(from, to);
}
}
fn main() {
let navigator = Navigator::new(WalkingStrategy);
navigator.route("Home", "Club");
navigator.route("Club", "Work");
let navigator = Navigator::new(PublicTransportStrategy);
navigator.route("Home", "Club");
navigator.route("Club", "Work");
}
Output
Walking route from Home to Club: 4 km, 30 min
Walking route from Club to Work: 4 km, 30 min
Public transport route from Home to Club: 3 km, 5 min
Public transport route from Club to Work: 3 km, 5 min
Functional approach
Functions and closures simplify Strategy implementation as you can inject behavior right into the object without complex interface definition.
It seems that Strategy is often implicitly and widely used in the modern development with Rust, e.g. it’s just like iterators work:
let a = [0i32, 1, 2];
let mut iter = a.iter().filter(|x| x.is_positive());
functional.rs
type RouteStrategy = fn(from: &str, to: &str);
fn walking_strategy(from: &str, to: &str) {
println!("Walking route from {} to {}: 4 km, 30 min", from, to);
}
fn public_transport_strategy(from: &str, to: &str) {
println!(
"Public transport route from {} to {}: 3 km, 5 min",
from, to
);
}
struct Navigator {
route_strategy: RouteStrategy,
}
impl Navigator {
pub fn new(route_strategy: RouteStrategy) -> Self {
Self { route_strategy }
}
pub fn route(&self, from: &str, to: &str) {
(self.route_strategy)(from, to);
}
}
fn main() {
let navigator = Navigator::new(walking_strategy);
navigator.route("Home", "Club");
navigator.route("Club", "Work");
let navigator = Navigator::new(public_transport_strategy);
navigator.route("Home", "Club");
navigator.route("Club", "Work");
let navigator = Navigator::new(|from, to| println!("Specific route from {} to {}", from, to));
navigator.route("Home", "Club");
navigator.route("Club", "Work");
}
Output
Walking route from Home to Club: 4 km, 30 min
Walking route from Club to Work: 4 km, 30 min
Public transport route from Home to Club: 3 km, 5 min
Public transport route from Club to Work: 3 km, 5 min
Specific route from Home to Club
Specific route from Club to Work