/ 设计模式 / 适配器模式 / Swift Swift 适配器模式讲解和代码示例 适配器是一种结构型设计模式, 它能使不兼容的对象能够相互合作。 适配器可担任两个对象间的封装器, 它会接收对于一个对象的调用, 并将其转换为另一个对象可识别的格式和接口。 进一步了解适配器模式 导航 简介 概念示例 Example Output 真实世界示例 Example Output 复杂度: 流行度: 使用示例: 适配器模式在 Swift 代码中很常见。 基于一些遗留代码的系统常常会使用该模式。 在这种情况下, 适配器让遗留代码与现代的类得以相互合作。 识别方法: 适配器可以通过以不同抽象或接口类型实例为参数的构造函数来识别。 当适配器的任何方法被调用时, 它会将参数转换为合适的格式, 然后将调用定向到其封装对象中的一个或多个方法。 以下示例可在 Swift Playgrounds 上使用。 感谢 Alejandro Mohamad 创建了Playground版本。 概念示例 真实世界示例 概念示例 本例说明了适配器设计模式的结构并重点回答了下面的问题: 它由哪些类组成? 这些类扮演了哪些角色? 模式中的各个元素会以何种方式相互关联? 了解该模式的结构后, 你可以更容易地理解下面基于真实世界的 Swift 应用案例。 Example.swift: 概念示例 import XCTest /// The Target defines the domain-specific interface used by the client code. class Target { func request() -> String { return "Target: The default target's behavior." } } /// The Adaptee contains some useful behavior, but its interface is incompatible /// with the existing client code. The Adaptee needs some adaptation before the /// client code can use it. class Adaptee { public func specificRequest() -> String { return ".eetpadA eht fo roivaheb laicepS" } } /// The Adapter makes the Adaptee's interface compatible with the Target's /// interface. class Adapter: Target { private var adaptee: Adaptee init(_ adaptee: Adaptee) { self.adaptee = adaptee } override func request() -> String { return "Adapter: (TRANSLATED) " + adaptee.specificRequest().reversed() } } /// The client code supports all classes that follow the Target interface. class Client { // ... static func someClientCode(target: Target) { print(target.request()) } // ... } /// Let's see how it all works together. class AdapterConceptual: XCTestCase { func testAdapterConceptual() { print("Client: I can work just fine with the Target objects:") Client.someClientCode(target: Target()) let adaptee = Adaptee() print("Client: The Adaptee class has a weird interface. See, I don't understand it:") print("Adaptee: " + adaptee.specificRequest()) print("Client: But I can work with it via the Adapter:") Client.someClientCode(target: Adapter(adaptee)) } } Output.txt: 执行结果 Client: I can work just fine with the Target objects: Target: The default target's behavior. Client: The Adaptee class has a weird interface. See, I don't understand it: Adaptee: .eetpadA eht fo roivaheb laicepS Client: But I can work with it via the Adapter: Adapter: (TRANSLATED) Special behavior of the Adaptee. 真实世界示例 Example.swift: 真实世界示例 import XCTest import UIKit /// Adapter Design Pattern /// /// Intent: Convert the interface of a class into the interface clients expect. /// Adapter lets classes work together that couldn't work otherwise because of /// incompatible interfaces. class AdapterRealWorld: XCTestCase { /// Example. Let's assume that our app perfectly works with Facebook /// authorization. However, users ask you to add sign in via Twitter. /// /// Unfortunately, Twitter SDK has a different authorization method. /// /// Firstly, you have to create the new protocol 'AuthService' and insert /// the authorization method of Facebook SDK. /// /// Secondly, write an extension for Twitter SDK and implement methods of /// AuthService protocol, just a simple redirect. /// /// Thirdly, write an extension for Facebook SDK. You should not write any /// code at this point as methods already implemented by Facebook SDK. /// /// It just tells a compiler that both SDKs have the same interface. func testAdapterRealWorld() { print("Starting an authorization via Facebook") startAuthorization(with: FacebookAuthSDK()) print("Starting an authorization via Twitter.") startAuthorization(with: TwitterAuthSDK()) } func startAuthorization(with service: AuthService) { /// The current top view controller of the app let topViewController = UIViewController() service.presentAuthFlow(from: topViewController) } } protocol AuthService { func presentAuthFlow(from viewController: UIViewController) } class FacebookAuthSDK { func presentAuthFlow(from viewController: UIViewController) { /// Call SDK methods and pass a view controller print("Facebook WebView has been shown.") } } class TwitterAuthSDK { func startAuthorization(with viewController: UIViewController) { /// Call SDK methods and pass a view controller print("Twitter WebView has been shown. Users will be happy :)") } } extension TwitterAuthSDK: AuthService { /// This is an adapter /// /// Yeah, we are able to not create another class and just extend an /// existing one func presentAuthFlow(from viewController: UIViewController) { print("The Adapter is called! Redirecting to the original method...") self.startAuthorization(with: viewController) } } extension FacebookAuthSDK: AuthService { /// This extension just tells a compiler that both SDKs have the same /// interface. } Output.txt: 执行结果 Starting an authorization via Facebook Facebook WebView has been shown /// Starting an authorization via Twitter The Adapter is called! Redirecting to the original method... Twitter WebView has been shown. Users will be happy :) 概念示例 真实世界示例