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

Дизайнерские шаблоны в Rust - фасад скрывающий сложный мир

Posted on:21 апреля 2023 г. at 09:23

Example Dynamic OG Image link

Вступление

Шаблон фасада используется как способ скрыть более сложную логику. Фасад может выполнять следующее:

Шаблон фасада обычно используется в следующих случаях:

На что это похоже? Что ж, это довольно просто:

Класс Facade имеет простой интерфейс, скрывающий тот факт, что он может иметь более сложное взаимодействие, например, с ClassA и ClassB. Этот пример простой, но вы можете себе представить, что в сложных системах существуют десятки или сотни классов, с которыми должен взаимодействовать фасад.

Реализация в Rust

В пустом каталоге откройте свой терминал или командную строку и введите:

cargo new rust_facade
cd rust_facade

Теперь откройте этот каталог в вашей любимой IDE и откройте main.rs файл в вашем каталоге src/.

Мы начнем с определения точечной структуры:

struct Point {
  x: f32,
  y: f32,
}

impl Point {
  fn new(x: f32, y: f32) -> Point {
    Point { x: x, y: y }
  }
}

Точка просто получает две координаты, X и Y. Я также добавил простой конструктор.

Структура ShapeMaker поможет нам построить квадрат:

struct ShapeMaker<'s> {
  p: &'s Point,
}

impl<'s> ShapeMaker<'s> {
  fn new(p: &'s Point) -> ShapeMaker<'s> {
    ShapeMaker { p: p }
  }

  fn create_square(&self,size: f32) -> Point {
    Point::new(self.p.x+size,self.p.y+size)
  }
}

Структура ShapeMaker просто получает отправную точку. Он вычисляет вторую точку квадрата в методе create_square(), добавляя параметр size как к координатам X, так и Y точки.

Структура ShapeMeasurer измеряет расстояние между двумя точками, используя теорему Пифогора:

struct ShapeMeasurer<'s> {
  first: &'s Point,
  second: &'s Point,
}

impl<'s> ShapeMeasurer<'s> {
  fn new(first: &'s Point, second: &'s Point) -> ShapeMeasurer<'s> {
    ShapeMeasurer { first: first, second: second }
  }

  fn get_distance(&self) -> f32 {
    let x = self.first.x - self.second.x;
    let y = self.first.y - self.second.y;
    (x*x + y*y).sqrt()
  }
}

Наконец, у нас есть измеритель площади, который, исходя из начальной точки и заданного размера, может измерить диагональ квадрата:

struct SquareMeasurer<'s> {
  starting_point: &'s Point,
}

impl<'s> SquareMeasurer<'s> {
  fn new(starting_point: &'s Point) -> SquareMeasurer<'s> {
    SquareMeasurer { starting_point: starting_point }
  }

  fn measure_square_diagonal(&self, size: f32) -> f32 {
    let p = ShapeMaker::new(self.starting_point).create_square(size);
    ShapeMeasurer::new(self.starting_point, &p).get_distance()
  }
}

Теперь мы можем это проверить:

fn main() {
  let p = Point::new(3.0, 4.0);
  let sm = SquareMeasurer::new(&p);
  println!("Diagonal of a square with size 3 is {}", sm.measure_square_diagonal(3.0));
}

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

  1. Мы создаем новую точку и передаем ее в SquareMeasurer.
  2. Вызывая метод measure_square_diagonal(), SquareMeasurer вызывает базовые классы, чтобы найти размер диагонали.
  3. Мы выводим результат. В нашем тестовом примере это должно быть около 4.2.

Вывод

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