Какие паттерны проектирования реализованы в Java
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны проектирования в Java
Design Patterns (паттерны проектирования) — это проверенные решения типичных архитектурных и дизайн-проблем. Java имеет богатую историю и множество паттернов, встроенных в язык, фреймворки и стандартные библиотеки. Давайте разберём основные категории.
Порождающие паттерны (Creational)
Отвечают за создание объектов.
1. Singleton
Гарантирует единственный экземпляр класса во всём приложении:
public class DatabaseConnection {
private static DatabaseConnection instance;
private DatabaseConnection() {}
public static synchronized DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
}
// Потокобезопасная реализация (eager initialization)
public class Logger {
private static final Logger INSTANCE = new Logger();
private Logger() {}
public static Logger getInstance() {
return INSTANCE;
}
}
// Bill Pugh Singleton (лучше всего)
public class ConfigManager {
private ConfigManager() {}
private static class SingletonHolder {
static final ConfigManager INSTANCE = new ConfigManager();
}
public static ConfigManager getInstance() {
return SingletonHolder.INSTANCE;
}
}
Использование в Java:
- Runtime.getRuntime()
- Desktop.getDesktop()
- Spring beans with singleton scope
2. Factory Method
Создаёт объекты без указания их конкретных классов:
interface PaymentProcessor {
void process(double amount);
}
class CreditCardProcessor implements PaymentProcessor {
@Override
public void process(double amount) {
System.out.println("Processing credit card payment: " + amount);
}
}
class PayPalProcessor implements PaymentProcessor {
@Override
public void process(double amount) {
System.out.println("Processing PayPal payment: " + amount);
}
}
public class PaymentProcessorFactory {
public static PaymentProcessor createProcessor(String type) {
return switch(type) {
case "credit_card" -> new CreditCardProcessor();
case "paypal" -> new PayPalProcessor();
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}
// Использование
PaymentProcessor processor = PaymentProcessorFactory.createProcessor("paypal");
processor.process(99.99);
Использование в Java:
- Collections.emptyList(), Collections.emptySet()
- Calendar.getInstance()
- DocumentBuilderFactory.newInstance()
- NumberFormat.getInstance()
3. Abstract Factory
Создание семейств объектов:
interface UIComponentFactory {
Button createButton();
TextField createTextField();
}
class WindowsUIFactory implements UIComponentFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
class MacUIFactory implements UIComponentFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
// Использование
UIComponentFactory factory = isWindows() ?
new WindowsUIFactory() : new MacUIFactory();
Button button = factory.createButton();
TextField textField = factory.createTextField();
4. Builder
Конструирование сложных объектов пошагово:
public class User {
private final String name;
private final String email;
private final int age;
private final String phone; // optional
private final String address; // optional
private User(Builder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public static class Builder {
private String name;
private String email;
private int age;
private String phone;
private String address;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
// Использование
User user = new User.Builder()
.name("Alice")
.email("alice@example.com")
.age(30)
.phone("+1234567890")
.build();
Использование в Java:
- StringBuilder
- ProcessBuilder
- HttpRequest.Builder (Java 11+)
- Lombok @Builder
5. Prototype
Копирование объектов:
public class Document implements Cloneable {
private String title;
private String content;
@Override
public Document clone() {
try {
return (Document) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
// Использование
Document original = new Document();
original.setTitle("Report");
original.setContent("Some content");
Document copy = original.clone();
copy.setTitle("Report Copy"); // Не влияет на original
Структурные паттерны (Structural)
Отвечают за построение отношений между объектами.
1. Adapter
Преобразует интерфейс одного класса в интерфейс другого:
interface LegacyPaymentSystem {
String makePayment(String accountId, double amount);
}
interface ModernPaymentInterface {
void pay(Payment payment);
}
public class PaymentAdapter implements ModernPaymentInterface {
private final LegacyPaymentSystem legacySystem;
public PaymentAdapter(LegacyPaymentSystem legacySystem) {
this.legacySystem = legacySystem;
}
@Override
public void pay(Payment payment) {
String result = legacySystem.makePayment(
payment.getAccountId(),
payment.getAmount()
);
if ("SUCCESS".equals(result)) {
payment.setStatus(PaymentStatus.COMPLETED);
}
}
}
Использование в Java:
- Collections.asSet(), Collections.asList() (wrapper adapters)
- InputStreamReader (adapter между InputStream и Reader)
2. Decorator
Добавляет функциональность к объекту динамически:
interface Coffee {
double cost();
String getDescription();
}
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 2.0;
}
@Override
public String getDescription() {
return "Simple Coffee";
}
}
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 0.5;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
}
public class CaramelDecorator extends CoffeeDecorator {
public CaramelDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 0.7;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Caramel";
}
}
// Использование
Coffee coffee = new SimpleCoffee(); // $2.0
coffee = new MilkDecorator(coffee); // $2.5
coffee = new CaramelDecorator(coffee); // $3.2
System.out.println(coffee.getDescription()); // "Simple Coffee, Milk, Caramel"
System.out.println(coffee.cost()); // 3.2
Использование в Java:
- Collections.synchronizedList(), Collections.unmodifiableList()
- BufferedInputStream, BufferedOutputStream (I/O decorators)
- Spring @Transactional, @Cacheable (annotations as decorators)
3. Facade
Предоставляет упрощённый интерфейс к сложной подсистеме:
// Сложная подсистема
class CPUSubsystem {
void execute() { System.out.println("CPU executing..."); }
}
class MemorySubsystem {
void load() { System.out.println("Loading to memory..."); }
}
class DiskSubsystem {
void read() { System.out.println("Reading from disk..."); }
}
// Facade
public class ComputerFacade {
private CPUSubsystem cpu;
private MemorySubsystem memory;
private DiskSubsystem disk;
public ComputerFacade() {
this.cpu = new CPUSubsystem();
this.memory = new MemorySubsystem();
this.disk = new DiskSubsystem();
}
public void start() {
disk.read();
memory.load();
cpu.execute();
}
}
// Использование
ComputerFacade computer = new ComputerFacade();
computer.start(); // Всё происходит за одним методом
Использование в Java:
- javax.faces (Java Server Faces)
- Spring's RestTemplate (упрощает работу с HTTP)
4. Proxy
Представляет подобный объект, контролирующий доступ к другому:
interface ImageLoader {
void display();
}
class RealImageLoader implements ImageLoader {
private String path;
public RealImageLoader(String path) {
this.path = path;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading image from disk: " + path);
}
@Override
public void display() {
System.out.println("Displaying: " + path);
}
}
class ImageLoaderProxy implements ImageLoader {
private RealImageLoader realLoader;
private String path;
public ImageLoaderProxy(String path) {
this.path = path;
}
@Override
public void display() {
if (realLoader == null) {
realLoader = new RealImageLoader(path); // Lazy initialization
}
realLoader.display();
}
}
// Использование
ImageLoader image = new ImageLoaderProxy("/path/to/image.jpg");
// Image не загружается до первого вызова display()
image.display(); // Здесь загружается и отображается
Использование в Java:
- Dynamic Proxies (java.lang.reflect.Proxy)
- Spring @Transactional proxies
- Hibernate lazy-loaded entities
5. Bridge
Отделяет абстракцию от реализации:
interface DrawingAPI {
void drawCircle(double x, double y, double radius);
}
class RedCircleDrawingAPI implements DrawingAPI {
@Override
public void drawCircle(double x, double y, double radius) {
System.out.println("Drawing red circle at (" + x + "," + y + ") radius=" + radius);
}
}
abstract class Shape {
protected DrawingAPI drawingAPI;
protected Shape(DrawingAPI drawingAPI) {
this.drawingAPI = drawingAPI;
}
abstract void draw();
}
class Circle extends Shape {
private double x, y, radius;
public Circle(double x, double y, double radius, DrawingAPI api) {
super(api);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
void draw() {
drawingAPI.drawCircle(x, y, radius);
}
}
Поведенческие паттерны (Behavioral)
Отвечают за взаимодействие между объектами.
1. Strategy
Определяет семейство алгоритмов и делает их взаимозаменяемыми:
interface SortingStrategy {
void sort(int[] array);
}
class QuickSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// QuickSort реализация
System.out.println("Sorting with QuickSort");
}
}
class MergeSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// MergeSort реализация
System.out.println("Sorting with MergeSort");
}
}
public class SortingContext {
private SortingStrategy strategy;
public SortingContext(SortingStrategy strategy) {
this.strategy = strategy;
}
public void executeSort(int[] array) {
strategy.sort(array);
}
}
// Использование
int[] array = {3, 1, 4, 1, 5, 9, 2, 6};
SortingContext context = new SortingContext(new QuickSortStrategy());
context.executeSort(array); // Выбираем алгоритм во время выполнения
context = new SortingContext(new MergeSortStrategy());
context.executeSort(array);
Использование в Java:
- Collections.sort() с Comparator
- java.lang.Comparable интерфейс
- Spring's TransactionManager implementations
2. Observer
Определяет один-ко-многим отношение между объектами:
interface Observer {
void update(String message);
}
class EmailObserver implements Observer {
@Override
public void update(String message) {
System.out.println("Sending email: " + message);
}
}
class SMSObserver implements Observer {
@Override
public void update(String message) {
System.out.println("Sending SMS: " + message);
}
}
class NewsPublisher {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void publishNews(String news) {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// Использование
NewsPublisher publisher = new NewsPublisher();
publisher.attach(new EmailObserver());
publisher.attach(new SMSObserver());
publisher.publishNews("Breaking news!"); // Оба получат уведомление
Использование в Java:
- java.util.Observer, java.util.Observable (deprecated)
- javax.swing events
- Spring's ApplicationEvent и @EventListener
- RxJava/Project Reactor
3. State
Позволяет объекту изменять своё поведение в зависимости от состояния:
interface State {
void processRequest(RequestContext context);
}
class PendingState implements State {
@Override
public void processRequest(RequestContext context) {
System.out.println("Request is pending, moving to processing");
context.setState(new ProcessingState());
}
}
class ProcessingState implements State {
@Override
public void processRequest(RequestContext context) {
System.out.println("Processing request, moving to completed");
context.setState(new CompletedState());
}
}
class CompletedState implements State {
@Override
public void processRequest(RequestContext context) {
System.out.println("Request completed");
}
}
public class RequestContext {
private State state = new PendingState();
public void setState(State state) {
this.state = state;
}
public void process() {
state.processRequest(this);
}
}
// Использование
RequestContext request = new RequestContext();
request.process(); // Pending -> Processing
request.process(); // Processing -> Completed
request.process(); // Completed
4. Command
Инкапсулирует запрос как объект:
interface Command {
void execute();
void undo();
}
class OpenFileCommand implements Command {
private String filename;
public OpenFileCommand(String filename) {
this.filename = filename;
}
@Override
public void execute() {
System.out.println("Opening file: " + filename);
}
@Override
public void undo() {
System.out.println("Closing file: " + filename);
}
}
public class CommandInvoker {
private Stack<Command> history = new Stack<>();
public void executeCommand(Command command) {
command.execute();
history.push(command);
}
public void undo() {
if (!history.isEmpty()) {
history.pop().undo();
}
}
}
// Использование
CommandInvoker invoker = new CommandInvoker();
invoker.executeCommand(new OpenFileCommand("document.txt"));
invoker.undo(); // Закрывает файл
5. Chain of Responsibility
Передача запроса вдоль цепи обработчиков:
abstract class RequestHandler {
protected RequestHandler nextHandler;
public void setNextHandler(RequestHandler handler) {
this.nextHandler = handler;
}
public void handle(Request request) {
if (canHandle(request)) {
process(request);
} else if (nextHandler != null) {
nextHandler.handle(request);
} else {
System.out.println("Request unhandled");
}
}
protected abstract boolean canHandle(Request request);
protected abstract void process(Request request);
}
class AuthenticationHandler extends RequestHandler {
@Override
protected boolean canHandle(Request request) {
return request.requiresAuth();
}
@Override
protected void process(Request request) {
System.out.println("Authenticating...");
}
}
class LoggingHandler extends RequestHandler {
@Override
protected boolean canHandle(Request request) {
return true; // Всегда логируем
}
@Override
protected void process(Request request) {
System.out.println("Logging request...");
}
}
6. Template Method
Определяет скелет алгоритма в базовом классе:
abstract class DataProcessor {
public final void process(String data) {
String raw = loadData(data);
String processed = validateAndProcess(raw);
saveResults(processed);
}
protected abstract String loadData(String data);
protected abstract String validateAndProcess(String data);
protected abstract void saveResults(String data);
}
class XMLDataProcessor extends DataProcessor {
@Override
protected String loadData(String data) {
return "Loaded XML: " + data;
}
@Override
protected String validateAndProcess(String data) {
return "Validated XML: " + data;
}
@Override
protected void saveResults(String data) {
System.out.println("Saved XML: " + data);
}
}
Использование в Java:
- java.io.InputStream.read(byte[])
- java.util.AbstractList
- Spring's AbstractApplicationContext
Архитектурные паттерны
Model-View-Controller (MVC)
User Input → Controller → Model → View → User
Model-View-ViewModel (MVVM)
View ↔ ViewModel ↔ Model
Dependency Injection
@Service
public class OrderService {
private final UserRepository userRepository;
public OrderService(UserRepository userRepository) {
this.userRepository = userRepository; // Инъекция через конструктор
}
}
Aspect-Oriented Programming (AOP)
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBeforeMethod(JoinPoint joinPoint) {
System.out.println("Calling: " + joinPoint.getSignature());
}
}
Таблица паттернов
| Паттерн | Тип | Задача |
|---|---|---|
| Singleton | Creational | Единственный экземпляр |
| Factory | Creational | Создание объектов |
| Builder | Creational | Построение сложных объектов |
| Adapter | Structural | Совместимость интерфейсов |
| Decorator | Structural | Добавление функционала |
| Proxy | Structural | Контроль доступа |
| Strategy | Behavioral | Взаимозаменяемые алгоритмы |
| Observer | Behavioral | Оповещение об изменениях |
| State | Behavioral | Изменение поведения |
| Command | Behavioral | Инкапсуляция операций |
| Template Method | Behavioral | Скелет алгоритма |
Паттерны проектирования — это не жесткие правила, а гибкие рекомендации. Используйте их когда они действительно помогают решить проблему, избегайте over-engineering.