派遣プログラマーになってから約4年経ちました。数々の試練を乗り越えて来ましたが、まだまだプログラミングの腕は未熟です^^;
プログラマーとして達人の域に達するにはどうしたら良いかと考えて、デザインパターンを学ぼうと決めました。
本日は、業務でも使っているSingletonパターンを学びます。
<目次>
Singletonとは
Singletonパターンは、プログラムの実行プロセスの中で、インスタンスを一つのみ生成することを保障したパターンです。
プログラムを書いていると「このインスタンスは一回しか作られないことを保障したいな」と思う時がたまにあります。
直近の業務だと、Redisへアクセスするインスタンスを作った時にSingletonを使いました。
Redisへアクセスできるインスタンスを不用意に作成したくなかったからです。
Go言語とPythonを使って、Singletonを実装してみましょう。
Go言語編
Go言語では、sync.Onceパッケージを利用することで、Singletonを実装できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package main import ( "fmt" "sync" ) // パッケージ外から呼び出されないようにlowercase type singletonDB struct { name string } func (db *singletonDB) GetDBInfo() string { return db.name } var once sync.Once var instance *singletonDB func GetSingletonDatabase(dbName string) *singletonDB { // once.Doで1回のみ実行できる関数を作成できる once.Do(func() { db := singletonDB{dbName} instance = &db }) return instance } func main() { db := GetSingletonDatabase("PostgreSQL") dbName := db.GetDBInfo() fmt.Println("DB Name: ", dbName) db2 := GetSingletonDatabase("MySQL") dbName2 := db2.GetDBInfo() fmt.Println("DB Name: ", dbName2) } |
GetSingletonDatabaseにDB名(PostgreSQL, MySQL)を渡して、インスタンスを生成しました。
実行してみましょう。
1 2 3 |
$ go run singleton.go DB Name: PostgreSQL DB Name: PostgreSQL |
PostgreSQLのみ作成されました。
このように、「生成できるインスタンスは一つ」であることを保障しています。
Python編
Go言語と違ってPythonにはClassがあるため、Type classを継承したSingletonクラスを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# typeclassを継承すること class Singleton(type): instance = {} def __call__(cls, *args, **kwargs): print("first call") if cls not in cls.instance: cls.instance[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls.instance[cls] class Database(metaclass=Singleton): def __init__(self, name): print("second call") self.name = name def get_db_info(self): print("third call") return self.name if __name__ == '__main__': db = Database("PostgreSQL") print("DB Name: ", db.get_db_info()) db2 = Database("MySQL") print("DB Name: ", db2.get_db_info()) |
type classを継承するとtype classの__call__メソッドが使えるようになります。
__call__メソッドは、インスタンスを関数のように呼び出した時に実行される特殊メソッドです。
SingletonにしたいクラスのメタクラスとしてSingletonクラスを渡すことで、継承先のクラス(ここではDatabase)がインスタンス化された時に、Singletonクラスに設定された__call__メソッドが実行されるようです。
そして、__call__メソッド内でインスタンス化のチェックを行い、未作成の場合はインスタンスを生成して返します。※作成済みの場合は、instance変数に保持されたインスタンスを返す
実行してみましょう。
1 2 3 4 5 6 7 |
first call second call third call DB Name: PostgreSQL first call third call DB Name: PostgreSQL |
DB Nameは、どちらもPostgreSQLですね。注目すべき点は、second callが一度しか呼ばれていないことです。
__init__は、インスタンス化された時に呼び出される特殊メソッドなので、Singletonが実装できていることがわかります。
おわりに
今回は、デザインパターンの一つであるSingletonパターンを学びました。
Singletonを活用すれば不用意なインスタンスを作成しなくて済む為、より自信を持ってプログラミングできるようになりますね^^
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。