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

Какие паттерны проектирования реализованы в Java

3.0 Senior🔥 201 комментариев
#SOLID и паттерны проектирования

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

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

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

Паттерны проектирования в 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());
    }
}

Таблица паттернов

ПаттернТипЗадача
SingletonCreationalЕдинственный экземпляр
FactoryCreationalСоздание объектов
BuilderCreationalПостроение сложных объектов
AdapterStructuralСовместимость интерфейсов
DecoratorStructuralДобавление функционала
ProxyStructuralКонтроль доступа
StrategyBehavioralВзаимозаменяемые алгоритмы
ObserverBehavioralОповещение об изменениях
StateBehavioralИзменение поведения
CommandBehavioralИнкапсуляция операций
Template MethodBehavioralСкелет алгоритма

Паттерны проектирования — это не жесткие правила, а гибкие рекомендации. Используйте их когда они действительно помогают решить проблему, избегайте over-engineering.