← Назад к вопросам

Приведи пример композиции в контексте ООП

2.3 Middle🔥 181 комментариев
#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Композиция в контексте ООП

Композиция это взаимоотношение между объектами, когда один объект содержит другой объект в качестве части. Это один из основных принципов объектно-ориентированного программирования.

Композиция vs Наследование

Наследование (IS-A отношение)

// Собака ЭТО животное
public class Animal {
    public void eat() { }
}

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dog eats");
    }
}

Композиция (HAS-A отношение)

// Человек ИМЕЕТ сердце, ноги, руки
public class Heart {
    public void beat() {
        System.out.println("Beat!");
    }
}

public class Human {
    private Heart heart;  // HAS-A отношение
    
    public Human() {
        this.heart = new Heart();
    }
    
    public void live() {
        heart.beat();
    }
}

Практический пример 1: Компьютер

// Компоненты компьютера
public class CPU {
    public void execute(String command) {
        System.out.println("Executing: " + command);
    }
}

public class RAM {
    private int capacity; // GB
    
    public RAM(int capacity) {
        this.capacity = capacity;
    }
    
    public void store(String data) {
        System.out.println("Storing: " + data);
    }
}

public class HardDrive {
    private int storage; // GB
    
    public HardDrive(int storage) {
        this.storage = storage;
    }
    
    public void save(String file) {
        System.out.println("Saving file: " + file);
    }
}

// Компьютер СОДЕРЖИТ компоненты
public class Computer {
    private CPU cpu;       // Композиция
    private RAM ram;       // Композиция
    private HardDrive hd;  // Композиция
    
    public Computer(int ramSize, int hddSize) {
        this.cpu = new CPU();
        this.ram = new RAM(ramSize);
        this.hd = new HardDrive(hddSize);
    }
    
    public void start() {
        System.out.println("Computer starting...");
        cpu.execute("BIOS");
        ram.store("OS");
        System.out.println("Computer started!");
    }
    
    public void saveFile(String filename) {
        ram.store(filename);
        hd.save(filename);
    }
}

// Использование
Computer myComputer = new Computer(16, 512);
myComputer.start();
myComputer.saveFile("document.pdf");

Практический пример 2: Заказ в интернет-магазине

public class Product {
    private String name;
    private double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    public String getName() { return name; }
    public double getPrice() { return price; }
}

public class OrderItem {
    private Product product;
    private int quantity;
    
    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }
    
    public double getTotalPrice() {
        return product.getPrice() * quantity;
    }
}

public class Customer {
    private String name;
    private String email;
    
    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    public String getName() { return name; }
}

public class Order {
    private String id;
    private Customer customer;           // Композиция
    private List<OrderItem> items;      // Композиция
    private LocalDateTime createdAt;
    
    public Order(String id, Customer customer) {
        this.id = id;
        this.customer = customer;
        this.items = new ArrayList<>();
        this.createdAt = LocalDateTime.now();
    }
    
    public void addItem(Product product, int quantity) {
        items.add(new OrderItem(product, quantity));
    }
    
    public double calculateTotal() {
        return items.stream()
            .mapToDouble(OrderItem::getTotalPrice)
            .sum();
    }
    
    public void printOrder() {
        System.out.println("Order #" + id);
        System.out.println("Customer: " + customer.getName());
        System.out.println("Items:");
        for (OrderItem item : items) {
            System.out.println("  - " + item.getProduct() + " x" + item.getQuantity());
        }
        System.out.println("Total: $" + calculateTotal());
    }
}

// Использование
Customer customer = new Customer("John Doe", "john@example.com");
Order order = new Order("ORD-001", customer);

Product laptop = new Product("Laptop", 999.99);
Product mouse = new Product("Mouse", 29.99);

order.addItem(laptop, 1);
order.addItem(mouse, 2);

order.printOrder();

Практический пример 3: Автомобиль

public class Engine {
    private String type;
    private int horsepower;
    
    public Engine(String type, int hp) {
        this.type = type;
        this.horsepower = hp;
    }
    
    public void start() {
        System.out.println("Engine started: " + type);
    }
}

public class Wheel {
    private String brand;
    private int size;
    
    public Wheel(String brand, int size) {
        this.brand = brand;
        this.size = size;
    }
}

public class Car {
    private String model;
    private Engine engine;           // Композиция
    private List<Wheel> wheels;     // Композиция (4 колеса)
    
    public Car(String model, Engine engine) {
        this.model = model;
        this.engine = engine;
        this.wheels = new ArrayList<>();
        
        // Добавляем 4 колеса
        for (int i = 0; i < 4; i++) {
            wheels.add(new Wheel("Michelin", 18));
        }
    }
    
    public void start() {
        engine.start();
        System.out.println(model + " is ready to go!");
    }
}

// Использование
Engine v8Engine = new Engine("V8 Petrol", 400);
Car ferrari = new Car("Ferrari F8", v8Engine);
ferrari.start();

Композиция vs Наследование

АспектНаследованиеКомпозиция
ОтношениеIS-AHAS-A
СвязьСильнаяСлабая
ГибкостьНизкаяВысокая
Переиспользование кодаНаследует все методыИспользует методы
ТестированиеСложнееПроще
РефакторингТрудныйПростой

Когда использовать Композицию

Пример 1: Попытка наследования - ПЛОХО

// Неправильно использовать наследование
public class Stack extends ArrayList {
    // Stack наследует ArrayList, но Stack НЕ является ArrayList!
    // Это нарушает принцип Liskov Substitution Principle
}

Пример 2: Правильно - Композиция

// Правильно использовать композицию
public class Stack<T> {
    private List<T> items = new ArrayList<>();
    
    public void push(T item) {
        items.add(item);
    }
    
    public T pop() {
        return items.remove(items.size() - 1);
    }
    
    public T peek() {
        return items.get(items.size() - 1);
    }
}

Преимущества Композиции

Гибкость - легко менять компоненты ✅ Слабая связанность - компоненты независимы ✅ Переиспользование - один компонент в разных контекстах ✅ Тестируемость - легче писать unit тесты ✅ Простота - не нужна сложная иерархия классов

Правило композиции

Favоrite Composition Over Inheritance (Предпочитай композицию наследованию)

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

Реальный пример из Spring Framework

// Spring использует композицию повсеместно
@Service
public class UserService {
    private UserRepository userRepository;       // Композиция
    private PasswordEncoder passwordEncoder;     // Композиция
    private EmailService emailService;           // Композиция
    
    @Autowired
    public UserService(UserRepository repo, 
                      PasswordEncoder encoder, 
                      EmailService email) {
        this.userRepository = repo;
        this.passwordEncoder = encoder;
        this.emailService = email;
    }
    
    public void registerUser(String email, String password) {
        User user = new User(email, passwordEncoder.encode(password));
        userRepository.save(user);
        emailService.sendConfirmation(email);
    }
}

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