Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Композиция в контексте ООП
Композиция это взаимоотношение между объектами, когда один объект содержит другой объект в качестве части. Это один из основных принципов объектно-ориентированного программирования.
Композиция 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-A | HAS-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);
}
}
Композиция это мощный инструмент для создания гибких, модульных и легких в поддержке приложений.