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

Какие знаешь архитектурные паттерны?

2.3 Middle🔥 161 комментариев
#SOLID и паттерны проектирования#Основы Java

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

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

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

Архитектурные паттерны в Java

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

1. Model-View-Controller (MVC)

MVC разделяет приложение на три слоя: данные (Model), представление (View) и логика (Controller).

// Model — бизнес-логика и данные
public class User {
    private String id;
    private String email;
    private String name;
    
    // Getters, setters
}

// Controller — обработка запросов
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable String id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(new UserDTO(user));
    }
    
    @PostMapping
    public ResponseEntity<UserDTO> createUser(@RequestBody CreateUserRequest request) {
        User user = userService.create(request);
        return ResponseEntity.status(201).body(new UserDTO(user));
    }
}

// View — представление (HTML, JSON)
// При REST API это обычно DTO или JSON

Преимущества:

  • Разделение ответственности
  • Легко тестировать
  • Переиспользуемые компоненты

Недостатки:

  • View и Model часто связаны
  • Может быть много логики в Controller

2. Model-View-ViewModel (MVVM)

MVVM добавляет ViewModel между Model и View для двусторонней связи.

// Model
public class UserModel {
    private String id;
    private String email;
}

// ViewModel — логика представления
public class UserViewModel {
    private final UserService userService;
    public Observable<String> userName = new Observable<>();
    
    public UserViewModel(UserService userService) {
        this.userService = userService;
    }
    
    public void loadUser(String id) {
        User user = userService.findById(id);
        userName.setValue(user.getName());
    }
    
    public void updateUserName(String newName) {
        userService.update(newName);
        userName.setValue(newName);
    }
}

// View
public class UserActivity extends AppCompatActivity {
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new UserViewModel(new UserService());
        
        // Bind к ViewModel
        viewModel.userName.observe(this, name -> {
            textView.setText(name);
        });
    }
}

Идеален для: мобильных приложений, где нужна двусторонняя связь

3. Layered Architecture (трёхслойная архитектура)

Layered — вертикальное разделение: Presentation → Business → Persistence.

// Presentation слой — REST API, UI
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable String id) {
        return new UserDTO(userService.findById(id));
    }
}

// Business слой — бизнес-логика
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    public User findById(String id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
    }
    
    public User create(CreateUserRequest request) {
        User user = new User(request.getEmail(), request.getName());
        return userRepository.save(user);
    }
}

// Persistence слой — доступ к БД
@Repository
public interface UserRepository extends JpaRepository<User, String> {
    Optional<User> findByEmail(String email);
}

Преимущества:

  • Понятная структура
  • Легко разбить команду
  • Стандартный подход

Недостатки:

  • Сложные зависимости между слоями
  • Не масштабируется для микросервисов

4. Clean Architecture (Onion Architecture)

Clean Architecture — зависимости направлены внутрь (от краёв к ядру).

// Domain слой (ядро) — независим от всего
public interface UserRepository {
    Optional<User> findById(String id);
    void save(User user);
}

public class User {
    private String id;
    private String email;
    
    public void changeEmail(String newEmail) {
        if (!newEmail.contains("@")) throw new InvalidEmailException();
        this.email = newEmail;
    }
}

// Application слой — use cases
@Service
public class CreateUserUseCase {
    private final UserRepository userRepository;
    
    public CreateUserUseCase(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User execute(CreateUserCommand command) {
        User user = new User(command.getEmail(), command.getName());
        userRepository.save(user);
        return user;
    }
}

// Infrastructure слой — реализация
@Component
public class JpaUserRepository implements UserRepository {
    @Autowired
    private UserJpaRepository jpaRepository;
    
    @Override
    public Optional<User> findById(String id) {
        return jpaRepository.findById(id).map(this::toDomain);
    }
    
    @Override
    public void save(User user) {
        jpaRepository.save(toJpa(user));
    }
}

// Presentation слой
@RestController
public class UserController {
    private final CreateUserUseCase createUserUseCase;
    
    public UserController(CreateUserUseCase createUserUseCase) {
        this.createUserUseCase = createUserUseCase;
    }
    
    @PostMapping("/users")
    public UserDTO create(@RequestBody CreateUserRequest request) {
        User user = createUserUseCase.execute(new CreateUserCommand(request));
        return new UserDTO(user);
    }
}

Преимущества:

  • Тестируемость (ядро независимо)
  • Гибкость (легко менять реализацию)
  • Соответствие DDD

Недостатки:

  • Больше кода и слоёв
  • Сложнее для маленьких проектов

5. Event-Driven Architecture

Event-Driven — компоненты взаимодействуют через события, не зная друг о друге.

// Event
public class UserCreatedEvent {
    private final String userId;
    private final String email;
    
    public UserCreatedEvent(String userId, String email) {
        this.userId = userId;
        this.email = email;
    }
}

// Publisher
@Service
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public User create(CreateUserRequest request) {
        User user = new User(request.getEmail(), request.getName());
        // Опубликовать событие
        eventPublisher.publishEvent(new UserCreatedEvent(user.getId(), user.getEmail()));
        return user;
    }
}

// Subscribers
@Component
public class EmailNotificationListener {
    @EventListener
    public void onUserCreated(UserCreatedEvent event) {
        // Отправить email
        System.out.println("Sending welcome email to: " + event.getEmail());
    }
}

@Component
public class LoggingListener {
    @EventListener
    public void onUserCreated(UserCreatedEvent event) {
        // Логирование
        System.out.println("User created: " + event.getUserId());
    }
}

Преимущества:

  • Слабая связанность
  • Легко добавлять новых подписчиков
  • Асинхронная обработка

Недостатки:

  • Сложнее отследить логику
  • Сложнее тестировать

6. CQRS (Command Query Responsibility Segregation)

CQRS разделяет команды (запись) от запросов (чтение).

// Command — изменение
public class UpdateUserCommand {
    public String userId;
    public String newEmail;
}

// Query — чтение
public class GetUserQuery {
    public String userId;
}

// Command Handler
@Service
public class UpdateUserCommandHandler {
    public void handle(UpdateUserCommand command) {
        User user = userRepository.findById(command.userId);
        user.setEmail(command.newEmail);
        userRepository.save(user);
        // Publish event
    }
}

// Query Handler (может использовать кэш, read-only БД)
@Service
public class GetUserQueryHandler {
    @Autowired
    private UserReadModel userReadModel;  // Оптимизирован для чтения
    
    public UserDTO handle(GetUserQuery query) {
        return userReadModel.findById(query.userId);
    }
}

Преимущества:

  • Независимое масштабирование чтения и записи
  • Оптимизированные модели для каждой операции
  • Асинхронное обновление

7. Microservices Architecture

Микросервисы — разбиение на независимые малые сервисы.

// User Service
@SpringBootApplication
@RestController
@RequestMapping("/api/users")
public class UserServiceApplication {
    
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable String id) {
        return userService.findById(id);
    }
}

// Order Service (вызывает User Service)
@Service
public class OrderService {
    @Autowired
    private RestTemplate restTemplate;
    
    public Order createOrder(CreateOrderRequest request) {
        // Вызов другого сервиса
        UserDTO user = restTemplate.getForObject(
            "http://user-service/api/users/" + request.getUserId(),
            UserDTO.class
        );
        
        Order order = new Order(request, user);
        return orderRepository.save(order);
    }
}

Преимущества:

  • Независимое развертывание
  • Выбор технологий для каждого сервиса
  • Масштабируемость

Недостатки:

  • Сложнее управлять
  • Проблемы с консистентностью данных
  • Требует хорошего мониторинга

Сравнение паттернов

ПаттернДляСложностьТестируемость
MVCWeb приложенияСредняяХорошая
MVVMМобильные приложенияСредняяОтличная
LayeredНебольшие проектыНизкаяСредняя
CleanБольшие проектыВысокаяОтличная
Event-DrivenАсинхронные системыВысокаяСредняя
CQRSСложные операцииВысокаяОтличная
MicroservicesМасштабируемые системыОчень высокаяСредняя

Выбор архитектуры зависит от размера проекта, команды и требований.

Какие знаешь архитектурные паттерны? | PrepBro