← Назад к вопросам
Как можно связать 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
Используй наиболее узкий уровень доступа
который позволяет коду работать корректно
Лучшие практики
- Начни с private — затем расширяй до package-private, protected, public
- Используй package-private для деталей реализации — которые не должны быть видны за пределами пакета
- Группируй связанные классы в пакеты — это позволяет использовать package-private для инкапсуляции
- Публичным должны быть только фасады и интерфейсы — не детали реализации
- Не создавай глубокие иерархии с protected — используй композицию вместо наследования
- Думай пакет как модуль — со своим публичным API и приватной реализацией