Builderパターン(1)

Rubyによるデザインパターン』(ラス・オルセン著 ピアソン・エデュケーション刊)の例をPythonに変換して書いています。目次


コンストラクタの引数がやたら多いなど、初期化が面倒なオブジェクトがあったとき、初期化をやりやすくするのが、Builderパターンです。

コンピュータ製造プログラムを作っているとします。

コンピュータには、ディスプレイの種類・マザーボード・DVDやHDのドライブなどによって、パラメータ化されています。さらに、マザーボードも複数の部品から出来ています。

class Computer(object):
    def __init__(self, display="crt", motherboard=Motherboard(), drives=[]):
        self.display = display
        self.motherboard = motherboard
        self.drives = drives

class CPU(object):
    #CPU共通のコード

class BasicCPU(object):
    #安いCPUについてのたくさんのコード
    
class TurboCPU(object):
    #超高速CPUについてのたくさんのコード

class Motherboard(object):
    def __init__(self, cpu=BasicCPU(), memory_size=1024):
        self.cpu = cpu
        self.memory_size = memory_size

class Drive(object):
    def __init__(self, type, size, writable):
        """ type: "harddistk" か "cd" か "dvd"
            size: MBで
            writable: 書き込み可能かどうか
        """
        self.type = type
        self.size = size
        self.writable = writable
#組み立ての実際
motherboard = Motherboard(TurboCPU(), 4000)

drives = []
drives.append(Drive("harddisk", 1024*1024*1024, True))
drives.append(Drive("dvd", 1024*4.7, True))
drives.append(Drive("dvd", 1024*8.5, False))

computer = Computer("lcd", motherboard, drives)

非常に単純なモデルにも関わらず、組み立てはかなり退屈な作業です。

この種の組み立てのロジックをカプセル化したのが、Builderです。

class ComputerBuilder(object):
    def __init__(self):
        self._computer = Computer()
    
    def set_turbo(self, has_turbo_cpu=True):
        if has_turbo_cpu:
            self._computer.motherboard.cpu = TurboCPU
        else:
            self._computer.motherboard.cpu = BasicCPU
    
    def set_display(self, display):
        self._computer.display = display
    
    def set_memory_size(self, size_in_mb):
        self._computer.motherboard.memory_size = size_in_mb
    
    def add_cd(self, writable=False):
        self._computer.drives.append(Drive("cd", 760, writable))

    def add_dvd(self, writable=False):
        self._computer.drives.append(Drive("dvd", 4000, writable))

    def add_harddisk(self, size_in_mb):
        self._computer.drives.append(Drive("harddisk", size_in_mb, True))
    
    def computer(self):
        return self._computer


#つかいかた
builder = ComputerBuilder()
builder.set_turbo()
builder.add_cd(True)
builder.add_dvd()
builder.add_harddisk(1024*1024*1024)

computer = builder.computer()

Builderはいわば、複数に分けられた__init__ です。一息に作る代わりに、何段階かに分けてオブジェクトを作るのです。