Вступление
Шаблон метода шаблона - это шаблон проектирования поведения, который позволяет вам определять шаблон или каркас операции в базовом классе, позволяя при этом подклассам переопределять определенные шаги или все шаги алгоритма без изменения его структуры.
Этот шаблон очень полезен, когда у вас есть ряд шагов, которые необходимо выполнить в определенном порядке, но вам нужны разные реализации в разных ситуациях.
Итак, на что это похоже? Ну, вот так:
Краткое объяснение:
- Перед производителем стоит задача произвести какой-то продукт, которым в данном случае может быть автомобиль или велосипед. Для производства этих продуктов необходимы два этапа.
- BikeProducer и CarProducer - это два производителя.
- Клиент использует как метод step1, так и метод step2 для получения продукта.
Поскольку Rust не поддерживает понятие суперклассов или абстрактных классов, мы можем реализовать это с помощью трейтов.
Реализация в Rust
Откройте свой терминал или командную строку в пустом каталоге и введите:
cargo new rust_template_pattern
cd rust_template_pattern
Откройте каталог в вашей любимой IDE и откройте main.rs
файл в каталоге src/
.
Сначала мы определим трейт:
trait Template {
fn add_frame(&self);
fn add_wheels(&self);
}
Как вы можете видеть, транспортное средство в нашем мире состоит всего лишь из рамы и колес. Обратите внимание на аргументы &self
для обоих методов, чтобы при необходимости мы могли обратиться к реализующей структуре.
Теперь определите CarProducer
:
struct CarProducer;
impl Template for CarProducer {
fn add_frame(&self) {
println!("Adding a car frame");
}
fn add_wheels(&self) {
println!("Adding 4 wheels");
}
}
Несколько примечаний:
- CarProducer - это пустая структура, поскольку в этом примере нам не нужны никакие данные в структуре.
- Все, что делают эти методы, - это распечатывают сообщение.
Производитель велосипедов похож:
struct BikeProducer;
impl Template for BikeProducer {
fn add_frame(&self) {
println!("Adding a bike frame");
}
fn add_wheels(&self) {
println!("Adding 2 wheels");
}
}
Теперь нам нужен метод, чтобы собрать все это:
fn produce_vehicle(producer:&dyn Template) {
producer.add_frame();
producer.add_wheels();
}
Этот метод получает один параметр, структуру, которая реализует трейт шаблона. Поскольку мы передаем трейт, мы используем ключевое слово dyn
.
Теперь пришло время проверить все это:
fn main() {
let producer = BikeProducer;
produce_vehicle(&producer);
}
Строка за строкой:
- Мы создаем структуру
BikeProducer
. - Мы передаем это в функцию
produce_vehicle
, мы можем это сделать, потому чтоBikeProducer
реализует трейт шаблона.
Альтернативная версия функции produce_vehicle
Если вы не хотите иметь параметр с dyn
, или возможно, вы считаете, что дженерики более удобочитаемы, вы всегда можете реализовать функцию produce_vehicle
следующим образом:
fn produce_vehicle<T: Template>(producer:&T) {
producer.add_frame();
producer.add_wheels();
}
На мой взгляд, это выглядит более читабельно, однако вы, конечно, вольны выбирать любой способ, все зависит от вашего вкуса и стиля программирования.
Вывод
Шаблон template
- один из самых простых в реализации шаблонов. Было довольно просто сделать это правильно в Rust, и я обнаружил, что использование дженериков может сделать вещи более удобочитаемыми.