Recherche…


Introduction

MVP est un modèle architectural, une dérivation du modèle – View – Controller. Il est représenté par trois composants distincts: Modèle, Vue et Présentateur. Il a été conçu pour faciliter les tests unitaires automatisés et améliorer la séparation des problèmes dans la logique de présentation.

Dans des exemples, vous trouverez un projet simple conçu en fonction du modèle MVP.

Remarques

Composants:

entrer la description de l'image ici

  • Le modèle est une interface responsable des données du domaine (à afficher ou à utiliser dans l'interface graphique)
  • View est responsable de la couche de présentation (GUI)
  • Le présentateur est le "intermédiaire" entre le modèle et la vue. Il réagit aux actions de l'utilisateur effectuées sur la vue, récupère les données du modèle et les formate pour les afficher dans la vue.

Devoir du composant:

Modèle Vue Présentateur
Communique avec le calque DB Rend les données Effectue des requêtes sur le modèle
Élever des événements appropriés Reçoit des événements Données de format du modèle
Logique de validation très basique Envoie des données formatées à la vue
Logique de validation complexe

Différences entre MVC et MVP :

  • View in MVC est étroitement lié au Controller, la partie View du MVP comprend à la fois UIViews et UIViewController
  • MVP View est aussi stupide que possible et ne contient pratiquement aucune logique (comme dans MVVM), MVC View possède une certaine logique métier et peut interroger le modèle
  • MVP View gère les gestes des utilisateurs et délègue les interactions au présentateur, dans MVC, le contrôleur gère les gestes et les commandes du modèle.
  • Le modèle MVP supporte fortement les tests unitaires, MVC a un support limité
  • MVC Controller a beaucoup de dépendances UIKit, MVP Presenter n'en a pas

Avantages:

  • MVP fait de UIViewController une partie du composant View, il est stupide, passif et moins massif;]
  • La plupart de la logique métier est encapsulée en raison des vues stupides, ce qui donne une excellente testabilité. Des objets simulés peuvent être introduits pour tester la partie domaine.
  • Les entités séparées sont plus faciles à garder en tête, les responsabilités sont clairement divisées.

Les inconvénients

  • Vous allez écrire plus de code.
  • Barrière pour les développeurs inexpérimentés ou pour ceux qui ne travaillent pas encore avec le modèle.

Dog.swift

import Foundation

enum Breed: String {
    case bulldog  = "Bulldog"
    case doberman = "Doberman"
    case labrador = "Labrador"
}

struct Dog {
    let name:  String
    let breed: String
    let age:   Int
}

DoggyView.swift

import Foundation

protocol DoggyView: NSObjectProtocol {
    func startLoading()
    func finishLoading()
    func setDoggies(_ doggies: [DoggyViewData])
    func setEmpty()
}

DoggyService.swift

import Foundation

typealias Result = ([Dog]) -> Void

class DoggyService {

    func deliverDoggies(_ result: @escaping Result) {
        
        let firstDoggy  = Dog(name: "Alfred", breed: Breed.labrador.rawValue, age: 1)
        let secondDoggy = Dog(name: "Vinny",  breed: Breed.doberman.rawValue, age: 5)
        let thirdDoggy  = Dog(name: "Lucky",  breed: Breed.labrador.rawValue, age: 3)

        let delay = DispatchTime.now() + Double(Int64(Double(NSEC_PER_SEC)*2)) / Double(NSEC_PER_SEC)
        
        DispatchQueue.main.asyncAfter(deadline: delay) {
            result([firstDoggy,
                    secondDoggy,
                    thirdDoggy])
        }
    }
}

DoggyPresenter.swift

import Foundation

class DoggyPresenter {

    // MARK: - Private
    fileprivate let dogService: DoggyService
    weak fileprivate var dogView: DoggyView?

    init(dogService: DoggyService){
        self.dogService = dogService
    }

    func attachView(_ attach: Bool, view: DoggyView?) {
        if attach {
            dogView = nil
        } else {
            if let view = view { dogView = view }
        }
    }

    func getDogs(){
        self.dogView?.startLoading()
    
        dogService.deliverDoggies { [weak self] doggies in
            self?.dogView?.finishLoading()
        
        if doggies.count == 0 {
            self?.dogView?.setEmpty()
        } else {
            self?.dogView?.setDoggies(doggies.map {
                return DoggyViewData(name: "\($0.name) \($0.breed)",
                                      age: "\($0.age)")
                })
            }
        }
    }
}

struct DoggyViewData {
    let name: String
    let age:  String
}

DoggyListViewController.swift

import UIKit

class DoggyListViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var emptyView: UIView?
    @IBOutlet weak var tableView: UITableView?
    @IBOutlet weak var spinner:   UIActivityIndicatorView?

    fileprivate let dogPresenter = DoggyPresenter(dogService: DoggyService())
    fileprivate var dogsToDisplay = [DoggyViewData]()

    override func viewDidLoad() {
        super.viewDidLoad()
    
        tableView?.dataSource = self
        spinner?.hidesWhenStopped = true
        dogPresenter.attachView(true, view: self)
        dogPresenter.getDogs()
    }

    // MARK: DataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dogsToDisplay.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
        let userViewData = dogsToDisplay[indexPath.row]
        cell.textLabel?.text = userViewData.name
        cell.detailTextLabel?.text = userViewData.age
        return cell
    }
}

extension DoggyListViewController: DoggyView {

    func startLoading() {
        spinner?.startAnimating()
    }

    func finishLoading() {
        spinner?.stopAnimating()
    }

    func setDoggies(_ doggies: [DoggyViewData]) {
        dogsToDisplay = doggies
        tableView?.isHidden = false
        emptyView?.isHidden = true;
        tableView?.reloadData()
    }

    func setEmpty() {
        tableView?.isHidden = true
        emptyView?.isHidden = false;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow