Buscar..


Introducción

MVP es un patrón arquitectónico, una derivación del Modelo – Vista – Controlador. Está representado por tres componentes distintos: Modelo, Vista y el Presentador. Fue diseñado para facilitar las pruebas de unidades automatizadas y mejorar la separación de inquietudes en la lógica de presentación.

En los ejemplos, encontrará un proyecto simple construido con el patrón MVP en mente.

Observaciones

Componentes:

introduzca la descripción de la imagen aquí

  • El modelo es una interfaz responsable de los datos del dominio (que se mostrarán o se ejecutarán en la GUI)
  • View es responsable de la capa de presentación (GUI)
  • Presenter es el "hombre medio" entre Model y View. Reacciona a las acciones del usuario realizadas en la Vista, recupera datos del Modelo y los formatea para mostrarlos en la Vista.

Deberes componentes:

Modelo Ver Presentador
Se comunica con la capa DB Renders datos Realiza consultas al modelo.
Levantando eventos apropiados Recibe eventos Formatos de datos del modelo
Lógica de validación muy básica. Envía datos formateados a la Vista
Lógica de validación compleja

Diferencias entre MVC y MVP :

  • La vista en MVC está estrechamente unida al controlador, la parte de vista del MVP consta de UIViews y UIViewController
  • MVP View es lo más tonto posible y casi no contiene lógica (como en MVVM), MVC View tiene cierta lógica de negocios y puede consultar el Modelo
  • MVP View maneja los gestos de los usuarios y delega la interacción con el Presentador, en MVC el Controlador maneja los gestos y comandos.
  • El patrón MVP es altamente compatible con Unit Testing, MVC tiene soporte limitado
  • MVC Controller tiene muchas dependencias de UIKit, MVP Presenter no tiene ninguna

Pros:

  • MVP hace que UIViewController sea parte del componente View, es tonto, pasivo y ... menos masivo;]
  • La mayor parte de la lógica empresarial está encapsulada debido a las vistas tontas, lo que proporciona una excelente capacidad de prueba. Se pueden introducir objetos simulados para probar la parte del dominio.
  • Las entidades separadas son más fáciles de mantener en mente, las responsabilidades están claramente divididas.

Contras

  • Escribirás más código.
  • Barrera para desarrolladores sin experiencia o para aquellos que aún no trabajan con el patrón.

Cambio de perro

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow