Design Pattern - Adapter Pattern


こんにちは!
今日はデザインPatternで学んだAdapter Patternをご紹介します!

Adapter Patternとは?


これは、2つのオブジェクトが類似した機能を有するがインタフェースに互換性がない場合に協働することを可能にする構造設計モードです.
  • 特定のオブジェクトのインタフェースを変換して、他のオブジェクトと一緒に使用します.

  • Client

  • プロトコルは
  • に依存する.
  • の既存の論理を含むオブジェクト
  • Protocol

  • は、既存の論理プロトコルをクライアントが使用するインタフェース
  • に変換する.
  • プロトコル
  • 他のオブジェクトを現在の論理に含める場合は、プロトコルに従う必要があります.

    Adapter

  • プロトコルを満たすために作成されたオブジェクト
  • は、クライアントおよびアダプタと対話するために使用されます.
  • Adapteeオブジェクトをクライアントインタフェースにカプセル化するか、またはクライアントオブジェクトをAdapteeで使用可能なフォーマット
  • に変換する.

    Adaptee

  • 外部ライブラリおよび外部システムオブジェクト
  • コードの例


    Adaptee

  • Naverに登録されている3 rdpartyクラス.
  • public class NaverAuthenticator {
        public func login(
            email: String,
            password: String,
            completion: @escaping (NaverUser?, Error?) -> Void
        ) {
            let token = "token"
            let user = NaverUser(email: email,
                                 password: password,
                                 token: token)
            completion(user, nil)
        }
    }
    
    public struct NaverUser {
        public var email: String
        public var password: String
        public var token: String
    }

    Protocol

  • email、パスワードは必須フィールドです.ログインに成功した場合はsuccessを呼び出してUserとTokenを使用します.
  • サードパーティオブジェクトを使用せずに、プロトコルを使用してログインを検証します.
  • 他のサードパーティ登録も、このプロトコルを使用して簡略化することができる.
  • protocol AuthenticationService {
        func login(
            email: String,
            password: String,
            success: @escaping (User, Token) -> Void,
            failure: @escaping (Error?) -> Void
        )
    }
    
    struct User {
        public let email: String
        public let password: String
    }
    
    struct Token {
        public let value: String
    }

    Adapter

  • プロトコルを用いてlogin()方法を実施する.
  • NaverAuthenticatorインスタンス専用.
  • に成功し、処理に失敗しました.
  • NaverAPIを直接知る必要はありません.
  • メンテナンス中に変更が発生した場合は、アダプタを変更するだけです.
  • class NaverAuthenticatorAdapter : AuthenticationService {
        private var authenticator = NaverAuthenticator()
        func login(
            email: String,
            password: String,
            success: @escaping (User, Token) -> Void,
            failure: @escaping (Error?) -> Void
        ) {
            authenticator.login(email: email, password: password) { (naverUser, error) in
                guard let naverUser = naverUser else {
                    failure(error)
                    return
                }
                let user = User(email: naverUser.email, password: naverUser.password)
                let token = Token(value: naverUser.token)
                success(user, token)
            }
        }
    }

    使用

  • AuthManger
    -依存プロトコル
    - authService.ログイン()コール
  • APIでAdapterが実装されている場合、アイデンティティマネージャインスタンスを作成するときは、Adapterを置き換えるだけです.
  • class AuthManager {
        var authService : AuthenticationService?
        
        init(authService: AuthenticationService) {
            self.authService = authService
        }
        
        func login() {
            authService?.login(
                email: "email",
                password: "password",
                success: { user, token in
                    print("Auth succeeded: \(user.email), \(token.value)")
                },
                failure: { error in
                    print("Auth failed")
                })
        }
    }
    
    let authManager = AuthManager(authService: NaverAuthenticatorAdapter())
    authManager.login()

    まとめ

  • Adapter Patternは、統合されたAPIを提供し、他のインタフェースのオブジェクトを使用する必要がある場合に負担を軽減する.
  • コードの鮮明さとシンプルさを向上させることで、外部オブジェクトを簡単に統合できます.
  • Adapterを1つのコードで置き換えるだけで、柔軟な応答を提供できます.
  • コードを修正する必要がある場合は、修正の負担が減少するため、これらのコードを使用することが望ましい.
  • リファレンス


    https://ko.wikipedia.org/wiki/%EC%96%B4%EB%8C%91%ED%84%B0_%ED%8C%A8%ED%84%B4
    https://haningya.tistory.com/265
    https://icksw.tistory.com/241
    https://medium.com/swiftcraft/swift-solutions-adapter-pattern-a2118a6a2910