#Abstract Factory
目次
オブジェクト指向の基本的な思想としてオブジェクト間の結合度が低いほうが良い、といったものがあります。
javaではinterfaceを用いることで、具象クラスを使う側が意識する必要がないようにできます。
インターフェース
interface Screen {
public void view();
}
具象クラス
public class TopScreen implements Screen {
public void view() {
System.out.println("トップ画面");
}
}
public class LoginScreen implements Screen {
public void view() {
System.out.println("ログイン画面");
}
}
使う側
public class Client {
public void displayTopScreen() {
Screen top = new TopScreen()
top.view();
}
public void displayLoginScreen() {
Screen login = new LoginScreen()
login.view();
}
}
一見なんの問題もないように見えますが、各クラスをインスタンス化する部分であるScreen top = new TopScreen()
とScreen login = new LoginScreen()
において、どうしても具象クラスを意識する必要がでてきます。
これは結合度が低いほうが良いという思想に反することになるうえ、使用しているコンストラクタを修正すればインスタンス化している箇所をすべて修正しなければならなくなります。
これをfactoryクラス
というインスタンスを生成してくれるクラスを作成することによって解決しますが、そのfactoryクラス
も抽象クラスと具象クラスに分けることで、より柔軟なオブジェクト生成工場を作ろうというのが本パターンです。
##目的
互いに関連したり依存し合うオブジェクト群を、その具象クラスを明確にせずに生成するためのインタフェースを提供する。
##構成要素
・AbstractFactory AbstractProductクラスを生成するインターフェースを定義する
・ConcreteFactory ConcreteProductクラスを生成するインターフェースを定義する
・AbstractProduct 生成される部品の共通部分を抽出した抽象クラス
・ConcreteProduct 生成される部品
・Client 利用者
##実装
ではサンプルコードです。
車に必要な部品を製造する工場を実装し、下記のようなフローでディーラーへ車両を陳列します。
ディーラーがメーカーへ車両を要求 -> メーカーが工場へ車用部品を要求 -> 工場がメーカーへ各種部品を返却 -> メーカーが車を組み立ててディーラーへ返却 -> ディーラーに車両が陳列される。
###AbstractFactory AbstractProductクラスを生成するインターフェースを定義する
車用部品製造工場クラス
package abstractfactory
open class CarFactory {
open fun makeEngine(displacement: Int): Engine {
return Engine(displacement)
}
open fun makeTire(position: Int): Tire {
return Tire(position)
}
open fun makeSteering(weight: Int): Steering {
return Steering(weight)
}
}
###AbstractProduct 生成される部品の共通部分を抽出した抽象クラス
エンジンクラス
package abstractfactory
open class Engine(displacement: Int) {
open val type = "普通のエンジン"
val displacement = displacement
}
タイヤクラス
package abstractfactory
open class Tire(position: Int) {
open val type = "普通のタイヤ"
val position = position
}
ハンドルクラス
package abstractfactory
class Steering(weight: Int) {
val type = "普通のハンドル"
val weight = weight
}
車クラス
package abstractfactory
open class Car(type: String, engine: Engine, tire: Tire, steering: Steering) {
val type = type
val engine = engine
val tire = tire
val steering = steering
fun getConstitution(): String {
return "【車種】:" + type + "," +
"【エンジン】:" + engine.type + "," +
"【タイヤ】:" + tire.type + "," +
"【ハンドル】:" + steering.type
}
}
###Client 利用者
自動車メーカークラス
package abstractfactory
class Maker {
/**
* 普通の車製造
*/
fun getCar(): Car {
return make("ファミリーカー", CarFactory())
}
/**
* 製造
*/
private fun make(type: String, factory: CarFactory): Car {
val engine = factory.makeEngine(1000)
val tire = factory.makeTire(1)
val steering = factory.makeSteering(100)
return Car(type, engine, tire, steering)
}
}
自動車ディーラークラス
package abstractfactory
class AutomobileDealer {
val cars = mutableListOf<Car>()
init {
openingUp()
}
/**
* ディーラーにある車一覧
*/
fun showCars() {
cars.forEach {
println(it.getConstitution())
}
}
/**
* 店舗開店
*/
private fun openingUp() {
val maker = Maker()
cars.add(maker.getCar())
}
}
###出力結果
AutomobileDealer#showCars()を呼び出せば、陳列されている車両(のスペック)が出力されます。
[output]
【車種】:ファミリーカー,【エンジン】:普通のエンジン,【タイヤ】:普通のタイヤ,【ハンドル】:普通のハンドル
以上で完成しましたが、突然社長が今までの製造ラインはそのままに、同様のラインでスーパーカー用部品も製造できる工場を作れといいだしました。
###ConcreteFactory ConcreteProductクラスを生成するインターフェースを定義する
スーパーカー用部品製造工場クラス
package abstractfactory
class SuperCarFactory: CarFactory() {
override fun makeEngine(displacement: Int): Engine {
return HiPerformanceEngine(displacement)
}
override fun makeTire(position: Int): Tire {
return HiGripTire(position)
}
}
###ConcreteProduct 生成される部品
高出力エンジンクラス
package abstractfactory
class HiPerformanceEngine(displacement: Int): Engine(displacement) {
override val type = "高出力エンジン"
}
ハイグリップタイヤクラス
package abstractfactory
class HiGripTire(position: Int): Tire(position) {
override val type = "ハイグリップタイヤ"
}
メーカーにスーパーカー製造メソッドを追加します。
###Client 利用者
メーカークラス
package abstractfactory
class Maker {
/**
* 車製造
*/
fun getCar(): Car {
return make(CarFactory())
}
/**
* スーパーカー製造
*/
fun getSuperCar(): Car {
return make("スーパーカー", SuperCarFactory())
}
/**
* 製造
*/
private fun make(type: String, factory: CarFactory): Car {
val engine = factory.makeEngine(1000)
val tire = factory.makeTire(1)
val steering = factory.makeSteering(100)
return Car(type, engine, tire, steering)
}
}
ディーラーは新たな車両(スーパーカー)をメーカーに要求します。
package abstractfactory
class AutomobileDealer {
val cars = mutableListOf<Car>()
init {
openingUp()
}
/**
* ディーラーにある車一覧
*/
fun showCars() {
cars.forEach {
println(it.getConstitution())
}
}
/**
* 店舗開店
*/
private fun openingUp() {
val maker = Maker()
cars.add(maker.getCar())
cars.add(maker.getSuperCar())
cars.add(maker.getSuperCar())
}
}
AutomobileDealer#showCars()を呼び出せば、スーパーカーが新たに陳列されていることがわかります。
###出力結果
[output]
【車種】:ファミリーカー,【エンジン】:普通のエンジン,【タイヤ】:普通のタイヤ,【ハンドル】:普通のハンドル
【車種】:スーパーカー,【エンジン】:高出力エンジン,【タイヤ】:ハイグリップタイヤ,【ハンドル】:普通のハンドル
【車種】:スーパーカー,【エンジン】:高出力エンジン,【タイヤ】:ハイグリップタイヤ,【ハンドル】:普通のハンドル
以上で社長の要求に応じることができました。