Suche…


Einführung

MVP ist ein Architekturmuster, eine Ableitung des Modell-Ansicht-Controllers. Es wird durch drei verschiedene Komponenten dargestellt: Modell, Ansicht und Präsentator. Es wurde entwickelt, um automatisierte Unit-Tests zu ermöglichen und die Trennung von Anliegen in der Präsentationslogik zu verbessern.

In Beispielen finden Sie ein einfaches Projekt, das mit dem MVP-Muster erstellt wurde.

Bemerkungen

Komponenten:

Geben Sie hier die Bildbeschreibung ein

  • Model ist eine Schnittstelle, die für die Domänendaten verantwortlich ist (die in der GUI angezeigt oder anderweitig bearbeitet werden sollen).
  • Ansicht ist für die Präsentationsschicht (GUI) verantwortlich
  • Presenter ist der "Mittelmensch" zwischen Model und View. Es reagiert auf die Aktionen des Benutzers, die in der Ansicht ausgeführt werden, ruft Daten aus dem Modell ab und formatiert sie für die Anzeige in der Ansicht

Pflichten der Komponente:

Modell Aussicht Moderator
Kommuniziert mit der DB-Schicht Rendert Daten Führt Abfragen an das Modell aus
Geeignete Ereignisse auslösen Empfängt Ereignisse Formatiert Daten von Model
Sehr grundlegende Validierungslogik Sendet formatierte Daten an die Ansicht
Komplexe Validierungslogik

Unterschiede zwischen MVC und MVP :

  • View in MVC ist eng mit dem Controller gekoppelt. Der View-Teil des MVP besteht aus UIViews und UIViewController
  • MVP View ist so dumm wie möglich und enthält fast keine Logik (wie in MVVM). MVC View verfügt über einige Geschäftslogik und kann das Modell abfragen
  • MVP View behandelt Benutzergesten und delegiert die Interaktion an den Presenter. In MVC verarbeitet der Controller Gesten und Befehle Modell
  • MVP-Pattern unterstützt Unit-Tests stark, MVC hat nur eingeschränkte Unterstützung
  • MVC Controller hat viele UIKit-Abhängigkeiten, MVP Presenter hat keine

Pros:

  • MVP macht UIViewController zu einem Teil der View-Komponente, dumm, passiv und ... weniger massiv;]
  • Der größte Teil der Geschäftslogik ist aufgrund der dummen Ansichten verkapselt. Dies ergibt eine hervorragende Testbarkeit. Zum Testen des Domänenteils können Mock-Objekte eingeführt werden.
  • Getrennte Einheiten sind leichter im Kopf zu halten, die Verantwortlichkeiten sind klar aufgeteilt.

Cons

  • Sie werden mehr Code schreiben.
  • Barriere für unerfahrene Entwickler oder für diejenigen, die noch nicht mit dem Muster arbeiten.

Hundewechsel

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow