7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Golangで、デザインパターン「Factory Method」を学ぶ

Last updated at Posted at 2020-03-22

GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。
取り上げられている実例は、JAVAベースのため、Pythonで同等のプラクティスに挑んだことがありました。
Qiita記事: "Pythonで、デザインパターン「Factory Method」を学ぶ"

今回は、Pythonで実装した” Factory Method”のサンプルアプリをGolangで実装し直してみました。

■ Factory Method(ファクトリメソッド)

Factory Method パターン(ファクトリメソッド・パターン)とは、GoF (Gang of Four; 四人組)によって定義されたデザインパターンの1つである。 Factory Method パターンは、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換えることで、 アプリケーションに特化したオブジェクトの生成をサブクラスに追い出し、クラスの再利用性を高めることを目的とする。
Virtual Constructor パターンとも呼ばれる。

UML class diagram

W3sDesign_Factory_Method_Design_Pattern_UML.jpg
1000px-Factory_Method_UML_class_diagram.svg.png
(以上、ウィキペディア(Wikipedia)より引用)

□ 備忘録

振る舞いに関するTemplate Methodパターンは、スーパークラスで処理の大枠を作って、サブクラスで具体的処理を決定するというもの。このTemplate Methodパターンを、インスタンスをつくる場面に適用したものが、Factory Methodパターンらしい。

■ "Factory Method"のサンプルプログラム

Factory Methodパターンは、以下の特徴があるようです。

  • インスタンスの作り方をスーパークラス側で定める
  • 具体的なクラス名までは定めない
  • 具体的な肉付けは、全てサブクラス側で行う

これによって、インスタンス作成のための枠組み(フレームワーク)と実際のインスタンス作成のクラスを分けて考えることができるようになるそうです。
実際に、Factory Methodパターンを使って、「身分証明書カード(IDカード)を作る工場」を題材としたサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

  • Hiroshi Yuki", Tomura, Hanako Satoの3名の身分証明書カードを作成する
  • Hiroshi Yuki", Tomura, Hanako Satoの3名の身分証明書カードを使用する
$ go run Main.go 
I'll create Hiroshi Yuki's card
I'll create Tomura's card
I'll create Hanako Sato's card
I'll use Hiroshi Yuki's card
I'll use Tomura's card
I'll use Hanako Sato's card

サンプルプログラムを動かしただけだと、いまいち、何がしたいのかよく分かりませんね
つづいて、サンプルプログラムの詳細を確認していきます。

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern_with_golang/tree/master/FactoryMethod

  • ディレクトリ構成
.
├── Main.go
└── framework
    ├── factory.go
    └── id_card_factory.go

(1) Product(製品)の役

Product役では、インスタンスが持つべきインタフェースを定めます。
サンプルプログラムでは、Productインタフェースが、この役を努めます。

framework/factory.go
package factoryMethod

... (snip)

// Product is interface
type Product interface {
	Use()
	getOwner() string
}

(2) Creator(作成者)の役

Creator役では、Productを生成する役割を担います。実際に生成するConcreteProduct役については何も知りません。
さらに、Creator役には、インスタンスの各部分を作るためのメソッドが用意されます。
サンプルプログラムでは、Factory構造体が、この役を努めます。

framework/factory.go
package factoryMethod

// FactoryInterface is interface
type FactoryInterface interface {
	createProduct(owner string) Product
	registerProduct(Product)
	Create(owner string) Product
}

// Factory is struct
type Factory struct {
	factory FactoryInterface
}

// Create func for creating product
func (f *Factory) Create(owner string) Product {
	p := f.factory.createProduct(owner)
	f.factory.registerProduct(p)
	return p
}

... (snip)

(3) ConcreteProduct(具体的製品)の役

ConcreteProduct役は、Product役のインタフェースを実装しているクラスです。実際のインスタンス作成後に呼び出されるメソッドが、ここで定義されます。
サンプルプログラムでは、iDCardProduct構造体が、この役を努めます。

framework/id_card_factory.go
package factoryMethod

... (snip)

type iDCardProduct struct {
	owner string
}

func newIDCardProduct(owner string) *iDCardProduct {
	fmt.Printf("I'll create %s's card\n", owner)
	return &iDCardProduct{owner}
}

// Use func for using card
func (i *iDCardProduct) Use() {
	fmt.Printf("I'll use %s's card\n", i.owner)
}

func (i *iDCardProduct) getOwner() string {
	return i.owner
}

(4) ConcreteCreator(具体的作成者)の役

ConcreteCreator役は、Creator役のインタフェースを実装しているクラスです。具体的な製品を作るクラスを定めます。
サンプルプログラムでは、IDCardFactory構造体が、この役を努めます。

framework/id_card_factory.go
package factoryMethod

import "fmt"

// IDCardFactory is struct
type IDCardFactory struct {
	*Factory
	owners []string
}

// NewIDCardFactory func for initializing IDCardFactory
func NewIDCardFactory() *IDCardFactory {
	idCardFactory := &IDCardFactory{
		Factory: &Factory{},
	}
	idCardFactory.factory = idCardFactory
	return idCardFactory
}

func (i *IDCardFactory) createProduct(owner string) Product {
	return newIDCardProduct(owner)
}

func (i *IDCardFactory) registerProduct(product Product) {
	i.owners = append(i.owners, product.getOwner())
}

... (snip)

(5) Client(依頼人)の役

サンプルプログラムでは、startMain関数が、この役を努めます。

Main.go
package main

import (
	factoryMethod "./framework"
)

func startMain(factoryObject factoryMethod.FactoryInterface) {
	card1 := factoryObject.Create("Hiroshi Yuki")
	card2 := factoryObject.Create("Tomura")
	card3 := factoryObject.Create("Hanako Sato")
	card1.Use()
	card2.Use()
	card3.Use()
}

func main() {
	startMain(factoryMethod.NewIDCardFactory())
}

■ 参考URL

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?