TableViewをDRYな设计にリファクタリングした话

“アプリ开発の工数の8割はTableViewに使われている”と言われることもある,アプリUIの花形TableView。荒れがちなTableView周りの设计について,ペイモでのリファクタリング事例を绍介します。

Controllerイモでは,共通のViewController ・ Presenterに分岐を书いてデータや机能に差分にTableViewでも无理やり复数画面で使い回していました。开発初期はこれでもよかったのですが,机能拡张に伴い特に使いしがの界界を迎えたため,今回绍介する设计へリファクタすることとなりました。

  • 同じようなデータを表示するTableViewが复数ある。
  • 各TableViewごとに微妙に机能差分(検索の有无,セル选択时の挙动の违い等)がある。
  • 一つのTableViewに复数种类のデータを表示する(「ユーザ情报」と「お知らせ」など)。
  • や仮ータの过滤器や仮名のインデックスなど,共通化したいロジックがある。

倾向于として,ペイモではClean Architectureを采用しています。

  1. ViewController→演示者→UseCase→存储库
    清洁建筑に则ってAPIコールします。
  2. 存储库→UseCase→数据模型
    APIの取得结果をドメイン层の责务范囲で整形してDataModelに积み,Presenterに返却します。
  3. 数据模型→演示者→ViewController
    Presenterは,UseCaseから返却されたDataModelからその画面の表示に必要なデータを取得してDataSourceを作成し,ViewControllerに引き渡します。
  • 枚举协议。
  ///セル用のデータ种别 
通讯协定CellRenderable {
//种别判定关数(TableViewのDelegateメソッドでの型判定に使用します)
func getType()-> CellDataType
} ///种别「A」のセル用データ
class CellTypeAData:CellRenderable {
func getType()-> CellDataType {
//自身のデータ种别を返します
返回.a
} //このデータ种别固有のプロパティ群
var hoge:字符串?
} ///种别「B」のセル用データ
class CellTypeBData:CellRenderable {
func getType()-> CellDataType {
返回.b
} //このデータ种别固有のプロパティ群
var hoge:字符串?
} ///主持人にデータを引き渡すモデル
类DataModel {
//このクラス内でデータ整形を行うのでカプセル化します
私有变量aDatas:[CellTypeAData] = []
private var bDatas:[CellTypeBData] = [] //プロトコル型で返すことで复数种类のセルがある场合も同じDataSourceとして扱えます
func getAData()-> [CellRenderable] {
//筛选などを実施
返回一个数据
} // Setterは省略
}
  • PresenterはDataModelからデータを「CellRenderableプロトコル型」として取り出し,TableViewのDelegateメソッドでキャストして适切なCellClassを决定します。こうすることで,复数种类のデータを一つのTableViewのDataSourceとしてまとめることができ,ロジックを単纯化できます。
  // ViewController内のTableViewのDelegateの実装部分を抜粋 
func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-> UITableViewCell {//演示者からCellRenderable型で数据を取り出します
保护数据= presenter.getRow(section:indexPath.section,row:indexPath.row)else {
返回UITableViewCell()
}

// CellRenderable#getTypeで种别を特定してキャストします
切换data.getType(){
案例.a:
让typeAData =数据为! CellTypeAData
//省略
案例.b:
让typeBData =数据为! CellTypeBData
//省略
}
}
  • にしておくイン层までをDRYにしておくと,メンテナンス性が确保できて改修コストが抑えられます。
  • 复数のデータ种别があっても枚举,Protocolで整理してやると取り回しよく実装できます。