#Composite
目次
**クラスを木構造で組み立てる。**とあるように、compositeとleafと呼ばれるオブジェクトで構成するパターンのようです。
##目的
部分―全体階層を表現するために、オブジェクトを木構造に組み立てる。Composite パターンにより、クライアントは、個々のオブジェクトとオブジェクトを合成したものを一様に扱うことができるようになる。
##構成要素
・Component 根、節、葉の抽象クラス
・Leaf 葉
・Composite 根または節
・Client 使用者
##実装
木構造と聞くとディレクトリツリーが思い浮かびますね。
ということでディレクトリツリーを管理、出力できるプログラムを実装します。
directoryがcompositeでfileがleafですね。
###Component 根、節、葉の抽象クラス
directoryとfileのインターフェース
package composite
interface Element {
enum class ElementType(val type: String) {
DIRECTORY("Direcotry"),
FILE("File")
}
fun getType(): ElementType
fun getName(): String
}
###Composite 根または節
directory抽象クラス
elementListを持たせ、自分の配下にいるElementを管理できるようにします。
package composite
abstract class AbstractDirectory: Element {
var elementList: MutableList<Element> = mutableListOf()
abstract fun addElement(element: Element)
}
directory具象クラス
package composite
class Directory(private val name: String): AbstractDirectory() {
override fun getType(): Element.ElementType {
return Element.ElementType.DIRECTORY
}
override fun addElement(element: Element) {
elementList.add(element)
}
override fun getName(): String {
return name
}
}
###Leaf 葉
file具象クラス
package composite
class File(private val name: String): Element {
override fun getType(): Element.ElementType {
return Element.ElementType.FILE
}
override fun getName(): String {
return name
}
}
###Client 使用者
ディレクトリツリーを管理する人
package composite
class DirectoryManager {
init {
// ルートフォルダ
val rootDirectory = Directory("/")
rootDirectory.addElement(File("sample.config"))
rootDirectory.addElement(File("gof.env"))
// iOSアプリ用フォルダ
val iosDirectory = Directory("iOS")
val iosAppDirectory = Directory("GofiOSApp")
iosAppDirectory.addElement(File("xcode.project"))
val iosAppSourceDirectory = Directory("Source")
iosAppSourceDirectory.addElement(File("hoge.swift"))
iosAppSourceDirectory.addElement(File("fuga.swift"))
iosDirectory.addElement(iosAppDirectory)
iosAppDirectory.addElement(iosAppSourceDirectory)
rootDirectory.addElement(iosDirectory)
// Androidアプリ用フォルダ
val androidDirectory = Directory("AndroidOS")
val androidAppDirectory = Directory("GofAndroidApp")
androidAppDirectory.addElement(File("AndroidManifest.xml"))
val androidAppSourceDirectory = Directory("Source")
androidAppSourceDirectory.addElement(File("moge.kt"))
androidAppSourceDirectory.addElement(File("unbaba.kt"))
androidDirectory.addElement(androidAppDirectory)
androidAppDirectory.addElement(androidAppSourceDirectory)
rootDirectory.addElement(androidDirectory)
show(rootDirectory, 0)
}
private fun show(element: Element, indent: Int) {
if (element is Directory) {
println("${"----".repeat(indent)}【${element.getType().type}】${element.getName()}")
element.elementList.forEach {
show(it, indent + 1)
}
} else {
println("${"----".repeat(indent)}【${element.getType().type}】${element.getName()}")
}
}
}
以上でcompositeパターンを用いたディレクトリツリーの完成です。
###出力結果
[output]
【Direcotry】/
----【File】sample.config
----【File】gof.env
----【Direcotry】iOS
--------【Direcotry】GofiOSApp
------------【File】xcode.project
------------【Direcotry】Source
----------------【File】hoge.swift
----------------【File】fuga.swift
----【Direcotry】AndroidOS
--------【Direcotry】GofAndroidApp
------------【File】AndroidManifest.xml
------------【Direcotry】Source
----------------【File】moge.kt
----------------【File】unbaba.kt
/iOS/GofIosApp/Sourceフォルダを同じ階層へ複製したくなった場合、iosAppDirectory.addElement(iosAppSourceDirectory)
を追加します。
[output]
【Direcotry】/
----【File】sample.config
----【File】gof.env
----【Direcotry】iOS
--------【Direcotry】GofiOSApp
------------【File】xcode.project
------------【Direcotry】Source
----------------【File】hoge.swift
----------------【File】fuga.swift
------------【Direcotry】Source
----------------【File】hoge.swift
----------------【File】fuga.swift
略
ディレクトリを自由自在に操れてます。
※kotlinは文字列操作なんかも簡潔に書けていいですね。