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

Как можно связать package private с инкапсуляцией?

1.0 Junior🔥 251 комментариев
#ООП#Основы Java

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

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

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

# Package-private и инкапсуляция в Java

Inкапсуляция — скрывание внутренней реализации деталей класса. Package-private (пакетный уровень доступа) — это мощный инструмент для реализации инкапсуляции на уровне пакета.

1. Уровни доступа в Java

// public — доступно всем
public class PublicClass {}

// protected — доступно в пакете и подклассах
protected class ProtectedClass {}

// package-private (default) — доступно только в пакете
class PackagePrivateClass {}

// private — доступно только в этом классе
private class PrivateClass {}

Матрица доступа:

                 Класс  Пакет  Подкласс  Везде
public            ✓      ✓       ✓       ✓
protected         ✓      ✓       ✓       -
package-private   ✓      ✓       -       -
private           ✓      -       -       -

2. Package-private для инкапсуляции на уровне пакета

Пример: платёжная система

// com.example.payment.api

// Публичный интерфейс
public interface PaymentProcessor {
    void processPayment(PaymentRequest request);
}

// Публичная фасада
public class PaymentService {
    private final PaymentProcessor processor;
    
    public PaymentService() {
        this.processor = new DefaultPaymentProcessor();
    }
    
    public void pay(PaymentRequest request) {
        processor.processPayment(request);
    }
}

// ---
// Это НЕ должно быть public! Используем package-private
class DefaultPaymentProcessor implements PaymentProcessor {
    private final PaymentValidator validator = new PaymentValidator();
    private final TransactionLogger logger = new TransactionLogger();
    
    @Override
    public void processPayment(PaymentRequest request) {
        validator.validate(request);  // package-private метод
        executeTransaction(request);  // package-private метод
        logger.logTransaction(request);  // package-private метод
    }
    
    private void executeTransaction(PaymentRequest request) {
        // Детали реализации
    }
}

// package-private класс — деталь реализации
class PaymentValidator {
    void validate(PaymentRequest request) {
        if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new InvalidPaymentException("Amount must be positive");
        }
    }
}

// package-private класс — деталь реализации
class TransactionLogger {
    void logTransaction(PaymentRequest request) {
        System.out.println("Transaction: " + request.getId());
    }
}

3. Инкапсуляция на разных уровнях

Уровень класса

// src/com/example/user/api/

// Публичный класс — основной интерфейс
public class UserService {
    private final UserRepository repository;
    
    public UserService(UserRepository repository) {
        this.repository = repository;
    }
    
    public User createUser(String name, String email) {
        validateInput(name, email);
        User user = new User(name, email);
        return repository.save(user);
    }
    
    private void validateInput(String name, String email) {
        // Приватный метод — не видим снаружи класса
    }
}

// Package-private класс — деталь реализации
class UserValidator {
    void validate(User user) {
        if (user.getName().isEmpty()) {
            throw new ValidationException("Name is required");
        }
    }
}

// Package-private интерфейс — используется только внутри пакета
interface UserCache {
    void cache(User user);
    User getCached(Long id);
}

// Package-private реализация
class InMemoryUserCache implements UserCache {
    private final Map<Long, User> cache = new ConcurrentHashMap<>();
    
    @Override
    public void cache(User user) {
        cache.put(user.getId(), user);
    }
    
    @Override
    public User getCached(Long id) {
        return cache.get(id);
    }
}

4. Package-private в многопакетной архитектуре

// src/com/example/order/api/ — публичный интерфейс
public class OrderService {
    private final OrderProcessor processor;
    
    public OrderService() {
        this.processor = new OrderProcessor();
    }
    
    public Order createOrder(OrderRequest request) {
        return processor.process(request);
    }
}

// src/com/example/order/internal/ — внутренняя реализация
class OrderProcessor {
    private final OrderValidator validator;
    private final PaymentService paymentService;
    private final NotificationService notificationService;
    
    OrderProcessor() {
        this.validator = new OrderValidator();
        this.paymentService = new PaymentService();
        this.notificationService = new NotificationService();
    }
    
    Order process(OrderRequest request) {
        validator.validate(request);
        Order order = createOrder(request);
        paymentService.processPayment(order);
        notificationService.notifyUser(order);
        return order;
    }
    
    private Order createOrder(OrderRequest request) {
        return new Order(request.getUserId(), request.getItems());
    }
}

// Package-private классы — не видны за пределами пакета
class OrderValidator {
    void validate(OrderRequest request) {}
}

class PaymentService {
    void processPayment(Order order) {}
}

class NotificationService {
    void notifyUser(Order order) {}
}

5. Паттерн: Package-private builder

// src/com/example/config/

public class ConfigService {
    private final AppConfig config;
    
    public ConfigService() {
        this.config = new ConfigBuilder()
            .withDatabaseUrl(System.getenv("DB_URL"))
            .withApiKey(System.getenv("API_KEY"))
            .build();
    }
    
    public AppConfig getConfig() {
        return config;
    }
}

// Package-private класс, используется только внутри пакета
class AppConfig {
    final String databaseUrl;
    final String apiKey;
    final int connectionPoolSize;
    
    private AppConfig(String databaseUrl, String apiKey, int connectionPoolSize) {
        this.databaseUrl = databaseUrl;
        this.apiKey = apiKey;
        this.connectionPoolSize = connectionPoolSize;
    }
}

// Package-private builder — скрывает сложность создания конфигурации
class ConfigBuilder {
    private String databaseUrl;
    private String apiKey;
    private int connectionPoolSize = 10;
    
    ConfigBuilder withDatabaseUrl(String url) {
        this.databaseUrl = url;
        return this;
    }
    
    ConfigBuilder withApiKey(String key) {
        this.apiKey = key;
        return this;
    }
    
    ConfigBuilder withConnectionPoolSize(int size) {
        this.connectionPoolSize = size;
        return this;
    }
    
    AppConfig build() {
        return new AppConfig(databaseUrl, apiKey, connectionPoolSize);
    }
}

6. Практический пример: система уведомлений

// src/com/example/notification/

// Публичный интерфейс
public class NotificationFacade {
    private final NotificationRouter router;
    
    public NotificationFacade() {
        this.router = new NotificationRouter();
    }
    
    public void sendNotification(Notification notification) {
        router.route(notification);
    }
}

// Package-private маршрутизатор
class NotificationRouter {
    private final EmailSender emailSender = new EmailSender();
    private final SmsSender smsSender = new SmsSender();
    private final PushSender pushSender = new PushSender();
    
    void route(Notification notification) {
        switch (notification.getType()) {
            case EMAIL -> emailSender.send(notification);
            case SMS -> smsSender.send(notification);
            case PUSH -> pushSender.send(notification);
            default -> throw new IllegalArgumentException("Unknown type");
        }
    }
}

// Package-private отправители
class EmailSender {
    void send(Notification notification) {
        // Реализация
    }
}

class SmsSender {
    void send(Notification notification) {
        // Реализация
    }
}

class PushSender {
    void send(Notification notification) {
        // Реализация
    }
}

7. Антипаттерн: избыточно публичный код

// ПЛОХО — всё публичное
public class UserService {
    public void createUser(String name) {
        validateName(name);  // Публичный
        checkIfUserExists(name);  // Публичный
        saveUser(name);  // Публичный
    }
    
    public void validateName(String name) {}  // Не должно быть публичным
    public void checkIfUserExists(String name) {}  // Не должно быть публичным
    public void saveUser(String name) {}  // Не должно быть публичным
}

// ХОРОШО — правильная инкапсуляция
public class UserService {
    public void createUser(String name) {
        validateName(name);
        checkIfUserExists(name);
        saveUser(name);
    }
    
    private void validateName(String name) {}  // Приватный
    private void checkIfUserExists(String name) {}  // Приватный
    private void saveUser(String name) {}  // Приватный
}

Правило пирамиды доступа

           public
          /  |  \
      protected package private
        \  |  /
          private

Используй наиболее узкий уровень доступа
который позволяет коду работать корректно

Лучшие практики

  1. Начни с private — затем расширяй до package-private, protected, public
  2. Используй package-private для деталей реализации — которые не должны быть видны за пределами пакета
  3. Группируй связанные классы в пакеты — это позволяет использовать package-private для инкапсуляции
  4. Публичным должны быть только фасады и интерфейсы — не детали реализации
  5. Не создавай глубокие иерархии с protected — используй композицию вместо наследования
  6. Думай пакет как модуль — со своим публичным API и приватной реализацией