デコレーターをSwift5で実装する
※この記事は「全デザインパターンをSwift5で実装する」https://qiita.com/satoru_pripara/items/3aa80dab8e80052796c6 の一部です。
The Decorator(デコレータ)
0. デコレータの意義
デコレータは、あるクラスなどに元は無かった振る舞いを追加するデザインパターンである。元のクラスのコードをいじることなく振る舞いを柔軟に変えることができる。
また継承を行うのとは違って、プログラム実行時に動的にデコレータを使用し機能拡張することもできる。
注意点としては、元のクラスと全く関連性がないような機能をデコレータで付け加えるのはよろしくないという事である。単一のクラスは単一の機能・責務だけを持つべきという「単一責務の原則」に反し、分かりづらく保守しにくいコードになってしまう。
※単一責務の原則については下記などを参照
https://qiita.com/decoy0318/items/f201b725e91a4a1bb4cf
Swiftではextensionを用いるか、デコレータクラスを新たに作る方法がある。
1. extensionを使う場合
extensionを使うと元のクラスにそのまま新しい機能を追加できるため非常に直感的で使いやすくなっている。
import UIKit
public extension UIColor {
//HTMLコード(#1411A4など)からUIColorインスタンスを作るイニシャライザを新設する
convenience init(hex: UInt32) {
let divisor = CGFloat(255)
let red = CGFloat((hex & 0xFF0000) >> 16) / divisor
let green = CGFloat((hex & 0x00FF00) >> 8) / divisor
let blue = CGFloat(hex & 0x0000FF) / divisor
self.init(red: red, green: green, blue: blue, alpha: 1)
}
}
ただしextensionには制約があり、ストアドプロパティを新設するor既存のストアドプロパティの振る舞いを変更することはできない。
※ストアドプロパティについては下記参照
https://qiita.com/akeome/items/2197a635ac616ab2f8e2
その場合には、下記のようにデコレータクラスを使うことになる。
2.デコレータクラスを使う場合
下記はUILabelにデコレータを使った例。
デコレータクラス自体が、目的のクラス(ここではUILabel)を継承する。
import UIKit
public class BorderedLabelDecorator: UILabel {
プロパティとしてもUILabelを保持する。
fileprivate let wrappedLabel: UILabel
UILabelの変数の振る舞いを変更していく。
public required init(label: UILabel, cornerRadius: CGFloat = 3.0, borderWidth: CGFloat = 1.0, borderColor: UIColor = .black) {
self.wrappedLabel = label
super.init(frame: label.frame)
self.wrappedLabel.layer.cornerRadius = cornerRadius
self.wrappedLabel.layer.borderWidth = borderWidth
self.wrappedLabel.layer.borderColor = borderColor.cgColor
self.wrappedLabel.clipsToBounds = true
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//使用予定のあるUILabelの変数をオーバーライドし、wrappedLabelとBorderedLabelDecoratorの変数がリンクするようにする
public override var textAlignment: NSTextAlignment {
get {
return self.wrappedLabel.textAlignment
}
set {
self.wrappedLabel.textAlignment = newValue
}
}
public override var backgroundColor: UIColor? {
get {
return self.wrappedLabel.backgroundColor
}
set {
self.wrappedLabel.backgroundColor = newValue
}
}
public override var textColor: UIColor? {
get {
return self.wrappedLabel.textColor
}
set {
self.wrappedLabel.textColor = newValue
}
}
public override var layer: CALayer {
return self.wrappedLabel.layer
}
//元のストアドプロパティの振る舞いを変更する(文字をセットした時に顔文字を付け加える)
public override var text: String? {
get {
return self.wrappedLabel.text
}
set {
var str = "🤔"
if let newVal = newValue {
str += newVal + str
}
self.wrappedLabel.text = str
}
}
}
参考文献: https://www.amazon.com/Design-Patterns-Swift-implement-Improve-ebook/dp/B07MDD3FQJ
Author And Source
この問題について(デコレーターをSwift5で実装する), 我々は、より多くの情報をここで見つけました https://qiita.com/satoru_pripara/items/32e8d4de8e36912051e8著者帰属:元の著者の情報は、元の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 .