3
9

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.

Pythonで、デザインパターン「Flyweight」を学ぶ

Last updated at Posted at 2020-01-23

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

■ Flyweight(フライウェイト・パターン)

Flyweightパターン(フライウェイト・パターン)とは、GoFによって定義されたデザインパターンの1つである。 等価なインスタンスを別々の箇所で使用する際に、一つのインスタンスを再利用することによってプログラムを省リソース化することを目的とする。

UML class and sequence diagram

W3sDesign_Flyweight_Design_Pattern_UML.jpg

UML class diagram

flyweight.png
(以上、ウィキペディア(Wikipedia)より引用)

□ 備忘録

flyweightというのは、「フライ級」のことで、ボクシングで最も体重が軽い階級を示すものであり、このデザインパターンでは、オブジェクトを「軽く」するためのものだそうです。
Flyweightパターンで使っている技法は、「インスタンスをできるだけ共有させて、無駄にnewしない」というもので、インスタンスが必要なときに、いつもnewするのではなく、すでに作ってあるインスタンスを利用できるなら、それを共有して使うものだそうです。
直感的に、デザインパターン「Singleton」の応用だと感じますね。

■ "Flyweight"のサンプルプログラム

##(1) 事前準備
アクキーアートっぽく、数字を表示するテキストファイルを準備しておきます。

big0.txt
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
big1.txt
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
big2.txt
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................

(以下、略)

(2) 動作確認

実際に、Flyweightパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

  • 引数の数字の順番に、指定された数字をアスキーアートで表示する
$ python Main.py 012123
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................

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

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

  • ディレクトリ構成
.
├── Main.py
├── big0.txt
├── big1.txt
├── big2.txt
├── big3.txt
├── big4.txt
├── big5.txt
├── big6.txt
├── big7.txt
├── big8.txt
├── big9.txt
└── flyweight
    ├── __init__.py
    └── big_char_factory.py

(1) Flyweight(フライ級)の役

普通に扱うとプログラムが重くなるので共有した方が良いものを表す役です。
サンプルプログラムでは、BigCharクラスが、この役を努めます。

flyweight/big_char_factory.py
class BigChar(object):
    def __init__(self, charname):
        try:
            with open("big{0}.txt".format(charname), 'r') as txtfile:
                data = txtfile.read()
            self.__fontdata = data
        except IOError:
            self.__fontdata = charname + '?'

    def __str__(self):
        return self.__fontdata

(2) FlyweightFactory(フライ級の工場)の役

Flyweightを作る工場の役です。この工場を使ってFlyweight役を作ると、インスタンスが共有されます。
サンプルプログラムでは、BigCharFactoryクラスが、この役を努めます。

flyweight/big_char_factory.py
class BigCharFactory(object):
    def __init__(self):
        self.__pool = {}

    @classmethod
    def getInstance(cls):
        if not hasattr(cls, "_instance"):
            cls._instance = cls()
        return cls._instance

    def getBigChar(self, charname):
        bc = self.__pool.get(charname)
        if bc is None:
            bc = BigChar(charname)
            self.__pool[charname] = bc
        return bc

(3) Client(依頼人)の役

FlyweightFactory役を使ってFlyweightを作り出し、それを利用する役です。
サンプルプログラムでは、BigStringクラスとstartMainメソッドが、この役を努めます。

flyweight/big_char_factory.py
class BigString(object):
    def __init__(self, string):
        self.bigchars = []
        self.factory = BigCharFactory.getInstance()
        for s in string:
            self.bigchars.append(self.factory.getBigChar(s))

    def print(self):
        for bc in self.bigchars:
            print(bc)
Main.py
import sys
from flyweight.big_char_factory import BigCharFactory, BigString

def startMain(string):
    bs = BigString(string)
    bs.print()

if __name__ == '__main__':
    startMain(sys.argv[1])

■ 参考URL

3
9
4

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
3
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?