Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Clean Architecture 2

Clean Architecture 2

Takuma Shimizu

August 29, 2018
Tweet

More Decks by Takuma Shimizu

Other Decks in Programming

Transcript

  1. લճͷ࿩୊ w ΫϦʔϯΞʔΩςΫνϟͷ؊ w #VTJOFTT3VMFT w &OUJUZ  $SJUJDBM 

    w 6TF$BTF "QQMJDBUJPOTQFDJpD  w ґଘΛҰํ޲ʹอͭ
  2. ࠓճͷ࿩୊ w &OUJUZ $SJUJDBM  w 6TF$BTF "QQMJDBUJPOTQFDJpD  w

    ࣸਅͷ&YJG΍.FUBEBUBΛѻ͏ΞϓϦ w -FWFM ϨΠϠʔ ؒͷσʔλͷड͚౉͠ํ๏
  3. &OUJUZ struct Metadata: Comparable { enum FlashMode { case none,

    normal, redEye } init(properties: [CFString : Any]) var localIdentifier: String { get } var iso: Float { get } var focalLength: Float { get } var exposureValue: Float { get } var lensAperture: Float { get } var exposureDuration: CMTime { get } var flashMode: FlashMode { get } ŋ ŋ ŋ }
  4. 6TF$BTF *' public protocol MetadataListInteractor { func browseMetadata() } public

    protocol MetadataListOutput : AnyObject { func didProvideMetadataToBrowse(_: [BrowsingMetadata]) } • MetadataListInteractor w "EBQUFS૚ͷ$POUSPMMFS͔Βར༻ • MetadataListOutput w "EBQUFS૚ͷ1SFTFOUFSͰ࣮૷ w 6TF$BTF *OUFSBDUPSͷ࣮૷ ͔Βར༻
  5. 6TF$BTF *NQ struct MetadataListUseCase: MetadataListInteractor { private let output: MetadataListOutput

    func browseMetadata() { let metadata = repository.fetchMetadata() let metadataToBrowse = metadata.map(BrowsingMetadata.init(_:)) output.didProvideMetadataToBrowse(metadataToBrowse) } }
  6. 6TF$BTF *NQ struct MetadataListUseCase: MetadataListInteractor { private let output: MetadataListOutput

    func browseMetadata() { let metadata = repository.fetchMetadata() let metadataToBrowse = metadata.map(BrowsingMetadata.init(_:)) output.didProvideMetadataToBrowse(metadataToBrowse) } }
  7. %BUB4USVDUVSF public struct BrowsingMetadata { public var localIdentifier: String {

    get } public var iso: Float { get } public var focalLength: Float? { get } public var exposureValue: Float { get } public var lensAperture: Float? { get } public var exposureDuration: CMTime { get } } extension BrowsingMetadata { private init(_ metadata: Metadata) }
  8. %BUB4USVDUVSF public struct BrowsingMetadata { public var localIdentifier: String {

    get } public var iso: Float { get } public var focalLength: Float? { get } public var exposureValue: Float { get } public var lensAperture: Float? { get } public var exposureDuration: CMTime { get } } extension BrowsingMetadata { private init(_ metadata: Metadata) }
  9. %BUB4USVDUVSF extension BrowsingMetadata { private init(_ metadata: Metadata) } w

    ϨϕϧؒΛ·͙ͨσʔλߏ଄ମͷड౉͠ w ԼҐϨϕϧ 6TF$BTF ্͕ҐϨϕϧͷ&OUJUZΛม׵ w .FNCFSXJTFJOJUJBMJ[FS *OUFSOBM  w ςετίʔυͷͨΊʹ࢒͓ͯ͘͠ w !UFTUBCMFJNQPSUͰར༻
  10. 6TF$BTF ௥Ճ public protocol OrderedMetadataListInteractor { func browseSortKeys() func browseOrderedMetadata(by

    key: MetadataListSortKey) } public protocol OrderedMetadataListOutput : AnyObject { func didProvideSortKeys(_: [MetadataListSortKey]) func didProvideSortedMetadataToBrowse(_: [BrowsingMetadata]) } public enum MetadataListSortKey { case iso, focalLength, exposureValue case lensAperture, exposureDuration } internal extension MetadataListSortKey : CaseIterable { }
  11. 6TF$BTF ௥Ճ internal extension MetadataListSortKey : CaseIterable { } public

    protocol OrderedMetadataListInteractor { func browseSortKeys() } public protocol OrderedMetadataListOutput : AnyObject { func didProvideSortKeys(_: [MetadataListSortKey]) }
  12. 6TF$BTF ௥Ճ public enum MetadataListSortKey { case iso, focalLength, exposureValue

    case lensAperture, exposureDuration } public protocol OrderedMetadataListInteractor { func browseOrderedMetadata(by key: MetadataListSortKey) } public protocol OrderedMetadataListOutput : AnyObject { func didProvideSortedMetadataToBrowse(_: [BrowsingMetadata]) }
  13. "EBQUFSͰ͸ • MetadataListInteractor ͱ OrderedMetadataListInteractor w ಉҰͷ$POUSPMMFS͔Βར༻ w $POUSPMMFS͕ͭͷ*OUFSBDUPSΛ࣋ͬͨঢ়ଶ •

    MetadataListOutput ͱ OrderedMetadataListOutput w ಉҰͷ1SFTFOUFSͰ࣮૷ w 1SFTFOUFS͕ͭͷ0VUQVUʹ४ڌͨ͠ঢ়ଶ
  14. <&OUJUZ> .FUBEBUB <6TF$BTF> .PEJpDBUJPO 6TF$BTF <*OQVU<I>> .PEJpDBUJPO *OUFSBDUPS <0VUQVU<I>> .PEJpDBUJPO

    0VUQVU <%BUB4USVDU> .PEJGZJOH .FUBEBUB 6* .FUBEBUB-JTU 6$ *0 0SEFSFE-JTU 6$ *0
  15. <&OUJUZ> .FUBEBUB <6TF$BTF> .PEJpDBUJPO 6TF$BTF <*OQVU<I>> .PEJpDBUJPO *OUFSBDUPS <0VUQVU<I>> .PEJpDBUJPO

    0VUQVU <%BUB4USVDU> .PEJGZJOH .FUBEBUB 6* .FUBEBUB-JTU 6$ *0 0SEFSFE-JTU 6$ *0
  16. &OUJUZ extension Metadata { func validate() -> Bool } w

    ػೳͷ௥Ճ͸ɺ&OUJUZʹ΋Өڹ͕ͰΔ w ػೳͷมߋ΋ಉ༷
  17. 6TF$BTF *' public struct ModifyingMetadata { public var localIdentifier: String

    { get } public var exposureValue: Float { get set } public var exposureDuration: CMTime { get set } } extension ModifyingMetadata { internal init(_ source: Metadata) } public protocol MetadataModificationInteractor { func requestToModifyMetadata(ofIdentifier localID: String) func modify(with modifyingMetadata: ModifyingMetadata) } public protocol MetadataModificationOutput : AnyObject { func didProvideMetadataToModify(_: inout ModifyingMetadata) func didModifyMetadata(_: ModifyingMetadata) func didFailToModifyMetadata(_: ModifyingMetadata) }
  18. 6TF$BTF *NQ struct MetadataModificationUseCase: MetadataModificationInteractor { private let output: MetadataModificationOutput

    func requestToModifyMetadata(ofIdentifier localID: String) { let source = repository.fetchMetadata( ofIdentifier: localID ) var metadataToModify = ModifyingMetadata(source) output.didProvideMetadataToModify(&metadataToModify) } }
  19. 6TF$BTF *NQ struct MetadataModificationUseCase: MetadataModificationInteractor { func modify(with modifyingMetadata: ModifyingMetadata)

    { let source = repository.fetchMetadata( ofIdentifier: modifyingMetadata.localIdentifier ) source.exposureValue = modifyingMetadata.exposureValue source.exposureDuration = modifyingMetadata.exposureDuration guard source.valiate() else { output.didFailToModifyMetadata(modifyingMetadata) return } repository.updatePhoto(with: source) output.didModifyMetadata(modifyingMetadata) } }
  20. %BUB4USVDUVSF public struct ModifyingMetadata { public var localIdentifier: String {

    get } public var exposureValue: Float { get set } public var exposureDuration: CMTime { get set } }
  21. %BUB4USVDUVSF public struct ModifyingMetadata { public var localIdentifier: String {

    get } public var exposureValue: Float { get set } public var exposureDuration: CMTime { get set } }
  22. <&OUJUZ> .FUBEBUB <6TF$BTF> .PEJpDBUJPO 6TF$BTF <*OQVU<I>> .PEJpDBUJPO *OUFSBDUPS <0VUQVU<I>> .PEJpDBUJPO

    0VUQVU <%BUB4USVDU> .PEJGZJOH .FUBEBUB 6* .FUBEBUB-JTU 6$ *0 0SEFSFE-JTU 6$ *0
  23. "MFSU$POUSPMMFS J04 w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹ protocol UserInformationUpdateOutput: AnyObject { func didFailToUpdateUserInformation(

    with error: Error, retrying: @escaping (Bool) -> Void ) } final class UserInformationPresenter: UserInformationUpdateOutput { func didFailToUpdateUserInformation( with error: Error, retrying: @escaping (Bool) -> Void) { let alert = // ... let retryAction = UIAlertAction(title: "Retry", style: .default) { _ in retrying(true) } alert.addAction(retryAction) let cancelAction = UIAlertAction(title: "Close", style: .cancel) { _ in retrying(false) } alert.addAction(cancelAction) view.show(alert) } }
  24. "MFSU$POUSPMMFS J04 w 1SFTFOUFSͰ"MFSU$POUSPMMFSΛੜ੒͢Δ৔߹ final class UserInformationUpdateUseCase: UserInfoUpdateInteractor { let

    output: UserInformationUpdateOutput func update(_ user: UserInformationUpdateOutput) { // ... let error = // ... output.didFailToUpdateUserInformation(with: error) { [weak self] isRetried in if isRetried { self?.update(user) } } } }
  25. "MFSU$POUSPMMFS J04 w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹ final class UserInformationPresenter: UserInfoUpdateOutput { let

    view: UserInformationView func didFailToUpdateUserInformation(with error: Error) { view.showError(withMessage: error.localizedDescription) } } final class UserInformationVC: UIVC, UserInfoView { func showError(withMessage message: String) { let alert = // ... let retry = UIAlertAction(title: "Retry", style: .default) { _ in controller.retry() } alert.addAction(retry) // ... present(alert, animated: true) } }
  26. "MFSU$POUSPMMFS J04 w 7JFXͰ"MFSU$POUSPMMFSΛੜ੒ɾදࣔ͢Δ৔߹ final class UserInformationUpdateUseCase: UserInfoUpdateInteractor { let

    output: UserInformationUpdateOutput func update(_ user: UserInformationUpdateOutput) { // ... let error = // ... output.didFailToUpdateUserInformation(with: error) } }