#Decorator
目次
いきなり話が脇道に逸れますが、デザインパターンやオブジェクト指向に関する書籍を読んでいるとよくオブジェクトに対する責務や責任といった言葉がでてきます。
これは当該オブジェクトにて出来なければならないことを指しています。
また単一責務の原則というのがありますが、これはクラスを変更する理由は1つであるべき、というものです。
例えば以下のようなクラスは修正する理由が2つあります。
- 画面遷移処理を追加したい→画面に関する変更理由
- 引き算処理を追加した→計算に関する変更理由
interface 画面計算 {
fun 描画(): Boolean
fun 足し算(num1: Int, num2: Int): Int
}
単一責務の原則に則ると以下のように分離すべきです。
interface 画面 {
fun 描画(): Boolean
fun 画面遷移(): Boolean
}
interface 計算 {
fun 足し算(num1: Int, num2: Int): Int
fun 引き算(num2: Int, num2: Int): Int
}
この単一責務の原則というのも、やはり変更に対して柔軟に対応するための考えだと理解しています。脇道話は以上です。
では本題、目的に責任を動的に追加するとあるので、継承を用いずにオブジェクト(インスタンス)に任意のタイミングで機能を追加していくようなパターンですね。
##目的
オブジェクトに責任を動的に追加する。Decorator パターンは、サブクラス化よりも柔軟な機能拡張方法を提供する。
##構成要素
・Component 責任を動的に追加できるインターフェースを定義した抽象クラス
・ConcreteComponent Componentクラスの具象クラス
・Decorator Componentクラスに責任を追加するインターフェースを定義した抽象クラス
・ConcreteDecorator Decoratorクラスの具象クラス
##実装
テキストビューインスタンスを生成するタイミングで、いろいろな機能を追加できるプログラムを実装します。
###Component 責任を動的に追加できるインターフェースを定義した抽象クラス
###Decorator Componentクラスに責任を追加するインターフェースを定義した抽象クラス
Viewコンポーネントインターフェース
package decorator
interface ViewComponent {
fun draw()
}
###ConcreteComponent Componentクラスの具象クラス
テキストビュー
package decorator
class TextView: ViewComponent {
override fun draw() {
print("【テキストビュー】")
}
}
###ConcreteDecorator Decoratorクラスの具象クラス
影をつけるデコレータ
package decorator
class ShadowDecorator(viewComponent: ViewComponent): ViewComponent {
val viewComponent = viewComponent
override fun draw() {
viewComponent.draw()
addShadow()
}
private fun addShadow() {
print(":影付き")
}
}
スクロールさせるデコレータ
package decorator
class ScrollDecorator(viewComponent: ViewComponent): ViewComponent {
val viewComponent = viewComponent
override fun draw() {
viewComponent.draw()
addScroll()
}
private fun addScroll() {
print(":スクロール可能")
}
}
部品が全部できました。使っていきましょう。
使う人
package decorator
class ComponentManager {
init {
// スクロール可能 影付き テキストビュー
val scrollShadowTextView = ScrollDecorator(ShadowDecorator(TextView()))
// スクロール可能 テキストビュー
val scrollTextView = ScrollDecorator(TextView())
// 描画
scrollShadowTextView.draw()
print("\n")
scrollTextView.draw()
}
}
###出力結果
実行すると以下のようになります。
[output]
【テキストビュー】:影付き:スクロール可能
【テキストビュー】:スクロール可能