Какие знаешь архитектурные паттерны?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Архитектурные паттерны в 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);
}
}
Преимущества:
- Независимое развертывание
- Выбор технологий для каждого сервиса
- Масштабируемость
Недостатки:
- Сложнее управлять
- Проблемы с консистентностью данных
- Требует хорошего мониторинга
Сравнение паттернов
| Паттерн | Для | Сложность | Тестируемость |
|---|---|---|---|
| MVC | Web приложения | Средняя | Хорошая |
| MVVM | Мобильные приложения | Средняя | Отличная |
| Layered | Небольшие проекты | Низкая | Средняя |
| Clean | Большие проекты | Высокая | Отличная |
| Event-Driven | Асинхронные системы | Высокая | Средняя |
| CQRS | Сложные операции | Высокая | Отличная |
| Microservices | Масштабируемые системы | Очень высокая | Средняя |
Выбор архитектуры зависит от размера проекта, команды и требований.