Перейти к содержанию

Шаблоны проектирования в Rust - Упрощеный метод создания шаблонов

Posted on:4 апреля 2023 г. at 08:41

Example Dynamic OG Image link

Вступление

Шаблон метода шаблона - это шаблон проектирования поведения, который позволяет вам определять шаблон или каркас операции в базовом классе, позволяя при этом подклассам переопределять определенные шаги или все шаги алгоритма без изменения его структуры.

Этот шаблон очень полезен, когда у вас есть ряд шагов, которые необходимо выполнить в определенном порядке, но вам нужны разные реализации в разных ситуациях.

Итак, на что это похоже? Ну, вот так:

Краткое объяснение:

  1. Перед производителем стоит задача произвести какой-то продукт, которым в данном случае может быть автомобиль или велосипед. Для производства этих продуктов необходимы два этапа.
  2. BikeProducer и CarProducer - это два производителя.
  3. Клиент использует как метод 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"); 
  } 
}

Несколько примечаний:

  1. CarProducer - это пустая структура, поскольку в этом примере нам не нужны никакие данные в структуре.
  2. Все, что делают эти методы, - это распечатывают сообщение.

Производитель велосипедов похож:

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); 
}

Строка за строкой:

  1. Мы создаем структуру BikeProducer.
  2. Мы передаем это в функцию produce_vehicle, мы можем это сделать, потому что BikeProducer реализует трейт шаблона.

Альтернативная версия функции produce_vehicle

Если вы не хотите иметь параметр с dyn, или возможно, вы считаете, что дженерики более удобочитаемы, вы всегда можете реализовать функцию produce_vehicle следующим образом:

fn produce_vehicle<T: Template>(producer:&T) { 
  producer.add_frame(); 
  producer.add_wheels(); 
}

На мой взгляд, это выглядит более читабельно, однако вы, конечно, вольны выбирать любой способ, все зависит от вашего вкуса и стиля программирования.

Вывод

Шаблон template - один из самых простых в реализации шаблонов. Было довольно просто сделать это правильно в Rust, и я обнаружил, что использование дженериков может сделать вещи более удобочитаемыми.