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

Как Presentation слой в MVP передает данные

2.0 Middle🔥 151 комментариев
#Архитектура и паттерны

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Передача данных из Presentation Layer в MVP

В архитектуре MVP (Model-View-Presenter), Presentation Layer (или Presenter) отвечает за бизнес-логику и управление View, выступая посредником между Model и View. Передача данных здесь двусторонняя: как от View к Presenter, так и от Presenter к View. Основные способы передачи данных из Presenter в View:

1. Интерфейсы View

View реализует интерфейс, который определяет методы для обновления UI. Presenter работает с этим интерфейсом, вызывая методы при изменении данных.

// Интерфейс View
interface UserProfileView {
    fun showUserData(user: User)
    fun showError(message: String)
    fun showLoading()
    fun hideLoading()
}

// Activity или Fragment реализует этот интерфейс
class UserProfileActivity : AppCompatActivity(), UserProfileView {
    private lateinit var presenter: UserProfilePresenter
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user_profile)
        presenter = UserProfilePresenter(this)
        presenter.loadUserData()
    }
    
    override fun showUserData(user: User) {
        nameTextView.text = user.name
        emailTextView.text = user.email
    }
    
    override fun showError(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
}

// Presenter вызывает методы View
class UserProfilePresenter(private val view: UserProfileView) {
    fun loadUserData() {
        view.showLoading()
        // Предположим, что это асинхронный вызов
        UserRepository.getUser { user ->
            view.hideLoading()
            if (user != null) {
                view.showUserData(user)
            } else {
                view.showError("Failed to load user")
            }
        }
    }
}

2. Колбэки и Listeners

Для обработки пользовательского ввода View передает в Presenter колбэки (например, через лямбды или интерфейсы).

// Presenter определяет интерфейс для событий
interface UserProfilePresenter {
    fun onSaveButtonClicked(name: String, email: String)
    fun onDeleteButtonClicked()
}

// Реализация Presenter
class UserProfilePresenterImpl(private val view: UserProfileView) : UserProfilePresenter {
    override fun onSaveButtonClicked(name: String, email: String) {
        if (name.isBlank()) {
            view.showError("Name cannot be empty")
            return
        }
        // Сохранение данных через Model
        UserRepository.saveUser(User(name, email))
        view.showSuccessMessage()
    }
}

3. Наблюдатели (Observers)

Использование реактивных подходов (например, RxJava или Kotlin Flow) для передачи потоков данных.

class UserProfilePresenter(private val view: UserProfileView) {
    private val disposable = CompositeDisposable()
    
    fun observeUserData() {
        UserRepository.getUserStream()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { user -> view.showUserData(user) },
                { error -> view.showError(error.message ?: "Unknown error") }
            ).addTo(disposable)
    }
    
    fun dispose() {
        disposable.dispose()
    }
}

4. Модели состояния (State Models)

Presenter формирует модели состояния (например, UserState), которые содержат все данные для отображения, и передает их целиком во View.

data class UserState(
    val isLoading: Boolean = false,
    val user: User? = null,
    val error: String? = null
)

class UserProfilePresenter(private val view: UserProfileView) {
    private var currentState = UserState()
    
    fun loadUserData() {
        currentState = currentState.copy(isLoading = true)
        view.render(currentState)
        
        UserRepository.getUser { user ->
            currentState = if (user != null) {
                currentState.copy(isLoading = false, user = user, error = null)
            } else {
                currentState.copy(isLoading = false, error = "Load failed")
            }
            view.render(currentState)
        }
    }
}

Ключевые принципы:

  • Разделение ответственности: Presenter не знает о деталях реализации View (только интерфейс), что упрощает тестирование.
  • Пассивная View: View не должна содержать бизнес-логики, только отображать данные и передавать события.
  • Управление жизненным циклом: Presenter должен учитывать жизненный цикл View (особенно на Android), чтобы избежать утечек памяти и crashes.
  • Тестируемость: Presenter легко тестировать с помощью unit-тестов, используя mock-объекты View.

Пример полного цикла передачи:

  1. ViewPresenter: Пользователь нажимает кнопку, View вызывает presenter.onButtonClicked().
  2. PresenterModel: Presenter запрашивает данные из Model (UserRepository.getUser()).
  3. ModelPresenter: Model возвращает данные (или ошибку) через колбэк.
  4. PresenterView: Presenter вызывает метод интерфейса View (view.showUserData(user)).

Этот подход обеспечивает чистую архитектуру, где Presentation Layer служит мостом между данными и их отображением, соблюдая принципы SOLID и тестируемости.

Как Presentation слой в MVP передает данные | PrepBro