Menu
Coddy logo textTech

Композиция

Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 55 из 61.

Многие объектно-ориентированные языки активно используют наследование для совместного использования функциональности между типами. Rust использует другой подход: композицию. Вместо наследования поведения от родительского типа вы создаёте сложные типы, включая другие типы в качестве полей.

Рассмотрим моделирование автомобиля. Вместо создания базового класса Vehicle и наследования от него вы создаёте Car из небольших специализированных компонентов:

struct Engine {
    horsepower: u32,
}

struct Wheels {
    count: u8,
    diameter: f32,
}

struct Car {
    engine: Engine,
    wheels: Wheels,
    brand: String,
}

Car не наследуется от Engine или Wheels. Он содержит их. Это отношение «имеет» называется композицией. Вы получаете доступ к внутренним компонентам через их поля и можете напрямую вызывать их методы:

impl Engine {
    fn start(&self) {
        println!("Engine with {} HP started!", self.horsepower);
    }
}

impl Car {
    fn start(&self) {
        self.engine.start();  // Делегировать внутреннему компоненту
    }
}

Этот шаблон позволяет сосредоточить каждую структуру на одной ответственности. Нужно изменить принцип работы двигателей? Измените только структуру Engine. Хотите повторно использовать Wheels для мотоцикла? Просто включите её в новую структуру. Композиция обеспечивает гибкость без тесной связанности, которую часто создаёт наследование.

challenge icon

Задание

Легко

Давайте создадим компьютерную систему с использованием композиции! Вместо создания одной огромной структуры вы составите Computer из небольших специализированных компонентов: CPU и Memory. Каждый компонент будет знать, как описать себя, а Computer будет делегировать работу своим частям.

Вы организуете код в трёх файлах:

  • cpu.rs: Define публичную структуру CPU с двумя публичными полями: cores (u32) для number ядер и speed_ghz (f32) для тактовой частоты. Добавьте specs method, который returns String с описанием CPU в формате {cores}-core @ {speed_ghz}GHz.
  • memory.rs: Define публичную структуру Memory с публичным полем size_gb (u32) для размера памяти. Добавьте specs method, который returns String в формате {size_gb}GB RAM.
  • main.rs: Подключите оба модуля и создайте публичную структуру Computer, которая has поле cpu типа CPU и поле memory типа Memory. Implement system_info method для Computer, который делегирует работу своим компонентам и выводит полную спецификацию системы. Используйте предоставленные inputs, чтобы создать Computer и отобразить его информацию.

Method system_info должен выводить:

System: {cpu_specs} | {memory_specs}

Например, для inputs 8, 3.5 и 16:

System: 8-core @ 3.5GHz | 16GB RAM

А для inputs 4, 2.8 и 32:

System: 4-core @ 2.8GHz | 32GB RAM

Вы получите три входных значения: количество ядер CPU (parse как u32), скорость CPU (parse как f32) и размер памяти (parse как u32).

Попробуйте сами

mod cpu;
mod memory;

use cpu::CPU;
use memory::Memory;

// TODO: Определите публичную структуру Computer с двумя публичными полями:
// - cpu: CPU
// - memory: Memory

// TODO: Реализуйте метод system_info у Computer, который:
// - Делегирует вызовы cpu.specs() и memory.specs()
// - Выводит: System: {cpu_specs} | {memory_specs}

fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let cores: u32 = input.trim().parse().expect("Invalid number");
    
    input.clear();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let speed_ghz: f32 = input.trim().parse().expect("Invalid number");
    
    input.clear();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let size_gb: u32 = input.trim().parse().expect("Invalid number");
    
    // TODO: Создайте экземпляры CPU и Memory, используя разобранные входные данные
    
    // TODO: Создайте экземпляр Computer с CPU и Memory
    
    // TODO: Вызовите system_info() у computer, чтобы вывести результат
}
quiz iconПроверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Rust