上一篇: Restructure 思考脈絡 1
延續上一篇的題目,在漸進式地增加功能:
將多個來源的資料,合併成一份資料後匯入系統
資料內有多筆細目,細目數量可能很大,且 process 的 memory 大小有限制
資料使用其中一欄做排序,由小到大,且唯一,
- 如果遇到值一樣的欄位,則取用在 array 中比較前面的 source
資料來源支援另一種輸入形式,輸入資料為與上次最後輸入的資料做差異,標記要新增或刪除的資料
不考慮在工作流程上的各種意外處理,先以單一化目前物件的工作能力來看,只要處理有關讀取/匯入資料的工作事項,因此:
- 每個資料來源 (source) 都應該提供各自的增、減資料
- 匯入時再合併增加 / 刪減的資料
- 增加是 增加沒有的資料 ,刪除是 刪除上次存在的資料 ,如果對同一個號碼在不同 source 中有「增加」或「刪除」,那應該要保留「增加」的指令
先來思考 source 提供的面向,要增加一個描述 RowDataOperation
來告訴 DataLoader
資料是增還是刪。開啟 source 時,要告訴他這次要拿的資料形式是 全拿(full)
還是 差異資料(diff)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| enum RowDataOperation { case add case remove }
protocol RowDataValue: Comparable { var operation: RowDataOperation { get } }
enum DataProvidingMode { case full case diff }
protocol SortedDataSource { associatedtype RowData: RowDataValue
func open(mode: DataProvidingMode) func next() -> Bool func getRowData() -> RowData func close() }
|
接著看 DataLoader
如何應用 source
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| class DataLoader<T: SortedDataSource> { var sources: [T] = [] func readMergedData(mode: DataProvidingMode, listMaxSize: Int, _ handler: ([T.RowData]) -> Void) { sources.forEach { (source) in source.open(mode: mode) } var temp: [T.RowData] = [] while hasNext() { let value = getMinRowDataSet() .select(by: mode)
temp.append(value!) if temp.count == listMaxSize { autoreleasepool { handler(temp) temp = [] } } } if temp.count > 0 { autoreleasepool { handler(temp) temp = [] } } sources.forEach { (source) in source.close() } } private func getMinRowDataSet() -> [T.RowData] { return [(sources.first?.getRowData())!] } private func hasNext() -> Bool { return false } }
extension Array where Element: RowDataValue { func select(by mode: DataProvidingMode) -> Element? { switch mode { case .diff: if count >= 2 && contains(where: { $0.operation == .add }) { return filter { $0.operation == .add }.first } else { return first } case .full: return first } } }
|
小結
以 Data Loader 的角度來說,他已經做好他的工作了
將輸入物件 (sources) 轉換成 讀取出來的物件 (系統支援的模式 .full mode / .diff mode)
接下來思考如何控制 Data Loader 在系統限制下的工作流程