
Strategy を Rust で
Strategy は、 振る舞いに関するデザインパターンの一つで、 一連の振る舞いをオブジェクトに転換し、 元のコンテキスト・オブジェクト内で交換可能とします。
元のオブジェクトは、 コンテキストと呼ばれ、 一つのストラテジー・オブジェクトへの参照を保持し、 それに振る舞いの実行を委任します。 コンテキストがその作業を実行する方法を変えるために、 他のオブジェクトが、 現在リンクされているオブジェクトを違うものと置き換えるかもしれません。
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