サーチ…
前書き
MVPは、Model-View-Controllerの派生物であるアーキテクチャパターンです。モデル、ビュー、およびプレゼンターの3つの異なるコンポーネントによって表されます。自動化されたユニットテストを容易にし、プレゼンテーションロジックにおける懸念の分離を改善するために設計されました。
例では、MVPパターンを念頭に置いた簡単なプロジェクトを見つけるでしょう。
備考
コンポーネント:
- モデルは、ドメインデータ(GUIに表示されるか、さもなければ動作する)を担当するインターフェースであり、
- ビューはプレゼンテーション層(GUI)を担当し、
- PresenterはModelとViewの中間的な人物です。これは、ビューで実行されたユーザーのアクションに反応し、モデルからデータを取得し、ビューに表示するためにフォーマットします
コンポーネントの任務:
モデル | ビュー | プレゼンター |
---|---|---|
DB層と通信する | データをレンダリングする | モデルへのクエリを実行します。 |
適切なイベントの提起 | イベントを受け取る | モデルからデータをフォーマットする |
非常に基本的な検証ロジック | フォーマットされたデータをビューに送信します。 | |
複雑な検証ロジック | ||
MVCとMVPの 違い :
- MVCのビューはコントローラと密接に結合されており、MVPのビュー部分はUIViewとUIViewControllerの両方で構成されています
- MVP Viewは可能な限りダムであり、MVVMのようなロジックはほとんど含まれていないため、MVC Viewにはビジネスロジックがあり、モデルをクエリできます
- MVPビューでは、ユーザーのジェスチャーを処理し、プレゼンターとの対話を委任します。MVCでは、コントローラーがジェスチャーとコマンドを処理します。モデル
- MVPパターンは高度にユニットテストをサポートし、MVCは限られたサポートを持っています
- MVC Controllerには多くのUIKit依存関係があり、MVP Presenterには何もありません
長所:
- MVPはUIViewControllerをViewコンポーネントの一部にしています。
- ビジネスロジックのほとんどは、ダムビューのためにカプセル化されています。これは優れたテスト容易性を提供します。 Mockオブジェクトを導入してドメイン部分をテストすることができます。
- 分離されたエンティティは頭に入れやすいので、責任は明確に分かれています。
短所
- より多くのコードを書くでしょう。
- 経験の浅い開発者やパターンをまだ使用していない人のための障壁。
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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow