アダプターをSwift5で実装する
※この記事は「全デザインパターンをSwift5で実装する」https://qiita.com/satoru_pripara/items/3aa80dab8e80052796c6 の一部です。
The Adapter(アダプター)
0. アダプターの意義
レガシーコード(古いコード)や、他者製のコード(外部ライブラリなど)を使う際、自分の書いたコードと実装形式などが違う事がある。そういったコードを用いる際、いちいち自分のコードと適合する形に直さなければならないとすると非常に手間がかかる。
アダプターパターンはそういったコードを自分のコードから扱いやすい形に修正してくれるデザインパターンである。
元のコードがどういった実装をしていたか? などをいちいち意識する事なく自分のコードに適合させられるため、時間と労力の節約につながる。
注意点としては、外部のコード等がもともと期待する機能を持っていないのにアダプターパターンを使って無理に他のコードと統合しようとしてはいけないという事である。それはアダプターの能力を超えている。そういったケースは単純に外部のコードの選定ミスなので、違うライブラリなど目的にあったコードを選ぶようにする。
1.アダプターを用いない場合
- プロトコル
PaymentGateway
に準拠している自前のクラスPayPal
とStripe
import Foundation
public protocol PaymentGateway {
func receivePayment(amount: Double)
var totalPayments: Double {get}
}
public class PayPal: PaymentGateway {
private var total = 0.0
public func receivePayment(amount: Double) {
self.total += amount
}
public var totalPayments: Double {
print("Total payments received via PayPal: \(self.total)")
return self.total
}
public init() {}
}
public class Stripe: PaymentGateway {
private var total = 0.0
public func receivePayment(amount: Double) {
self.total += amount
}
public var totalPayments: Double {
print("Total payments received via Venmo: \(self.total)")
return self.total
}
public init() {}
}
-
PaymentGateway
に準拠していない外部のコード由来(という設定)のAmazonPayments
クラス
import Foundation
//Third-party class that does not conform to PaymentGateway protocol.
public class AmazonPayments {
public var payments = 0.0
public func paid(value: Double, currency: String) {
self.payments += value
print("Paid \(currency)\(value) via Amazon Payments")
}
public func fulfilledTransactions() -> Double {
return self.payments
}
public init() {}
}
-
AmazonPayments
クラスだけは、他のクラスと一緒に処理する事ができない
let paypal = PayPal()
paypal.receivePayment(amount: 100)
paypal.receivePayment(amount: 200)
paypal.receivePayment(amount: 499)
let stripe = Stripe()
stripe.receivePayment(amount: 5.99)
stripe.receivePayment(amount: 25)
stripe.receivePayment(amount: 9.99)
let amazonPayments = AmazonPayments()
amazonPayments.paid(value: 120, currency: "USD")
amazonPayments.paid(value: 74.99, currency: "USD")
var paymentGateways: [PaymentGateway] = [paypal, stripe]//AmazonPaymentsクラスは配列に追加する事ができない
var total = 0.0
paymentGateways.forEach {total += $0.totalPayments}
print(total)
2. アダプターの実装
-
PaymentGateway
プロトコルに準拠したAmazonPaymentsAdapter
クラスを作成し、AmazonPayments
クラスを処理させる
import Foundation
public class AmazonPaymentsAdapter: PaymentGateway {
public func receivePayment(amount: Double) {
self.amazonPayments.paid(value: amount, currency: "USD")
}
public var totalPayments: Double {
let total = self.amazonPayments.payments
print("Total payments received via Amazon Payments: \(total)")
return total
}
//AmazonPaymentsクラスを変数として持ち、扱いやすいように処理する。
//外部からのアクセスを防ぐため、private修飾子をつける。
private let amazonPayments = AmazonPayments()
public init() {}
}
- 使用例
let paypal = PayPal()
paypal.receivePayment(amount: 100)
paypal.receivePayment(amount: 200)
paypal.receivePayment(amount: 499)
let stripe = Stripe()
stripe.receivePayment(amount: 5.99)
stripe.receivePayment(amount: 25)
stripe.receivePayment(amount: 9.99)
//アダプターを使用する事で、AmazonPaymentsクラスには直接触らなくて済む
let amazonPaymentsAdapter = AmazonPaymentsAdapter()
amazonPaymentsAdapter.receivePayment(amount: 120)
amazonPaymentsAdapter.receivePayment(amount: 74.99)
var paymentGateways: [PaymentGateway] = [paypal, stripe, amazonPaymentsAdapter]//アダプターを介して、AmazonPaymentsクラスを自作クラスと同じ型として扱えるようになった。
3. extensionを用いたアダプター
Swiftの機能としてextensionというものがある。これは、既存のクラスに自作の変数や関数などを追加できるというSwiftの機能である。
※詳細は
https://www.sejuku.net/blog/33334
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
などを参照
さらには、extensionを使って、今まで準拠していなかったプロトコルに準拠させるということもできる。
アダプターパターンの実現に当たって、より直感的な実装が可能となる。
本プログラムにおいては、PaymentGateway
プロトコルに準拠していなかったため扱いづらかったAmazonPayments
クラスを、extensionにより準拠させる事ができる。
AmazonPaymentsAdapter
というアダプタークラスを別に作る必要がないため、非常に便利と言える。
//extensionによりPaymentGatewayプロトコルに準拠させる。
extension AmazonPayments: PaymentGateway {
public func receivePayment(amount: Double) {
self.paid(value: amount, currency: "USD")
}
public var totalPayments: Double {
let total = self.payments
print("Total payments received via Amazon Payments: \(total)")
return total
}
}
let paypal = PayPal()
paypal.receivePayment(amount: 100)
paypal.receivePayment(amount: 200)
paypal.receivePayment(amount: 499)
let stripe = Stripe()
stripe.receivePayment(amount: 5.99)
stripe.receivePayment(amount: 25)
stripe.receivePayment(amount: 9.99)
let amazonPayments = AmazonPayments()
amazonPayments.receivePayment(amount: 120)
amazonPayments.receivePayment(amount: 74.99)
//AmazonPayments型を自作クラスと同じ型の配列に入れられるようになった
var paymentGateways: [PaymentGateway] = [paypal, stripe, amazonPayments]
参考文献: https://www.amazon.com/Design-Patterns-Swift-implement-Improve-ebook/dp/B07MDD3FQJ
Author And Source
この問題について(アダプターをSwift5で実装する), 我々は、より多くの情報をここで見つけました https://qiita.com/satoru_pripara/items/1754a6f78d5d22afd6fc著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .