月別アーカイブ: 5月 2010

[GoF]Mediatorパターンをpythonで書いてみた

Mediatorパターンをpython2.6で書いてみた。
たったひとりの相談役。親がすべての子供の状態を管理します。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)


class Child(object): # 相談する人(子) 一般名称はColleague:同僚
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def set_mother(self, mother): # 親のいる場所を記憶(宣言)
        pass
    
    @abc.abstractmethod
    def set_enabled(self, enabled): # 親の言う事を聞く(宣言)
        pass
        

class Mother(object): # 相談され人(親) 一般名称はMediator:相談役
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def child_changed(self, child): # 子に変更があった時(宣言)
        pass
        

class Heroine(Child): # 子の実装
    def __init__(self, name):
        self.__name = name
        self.__system = None
        self.__likelevel = 0
        self.__h_scene = False
    
    def set_mother(self, mother): # 親を記憶(実装)
        self.__system = mother
    
    def set_enabled(self, enabled): # 親の言うことを聞く(実装)
        self.__h_scene = enabled # 
    
    @property
    def name(self): return self.__name
    
    @property
    def likelevel(self): return self.__likelevel
    
    def likelevelup(self):
        self.__likelevel += 1
        # 自分自身に変更があったことを親に伝える
        self.__system.child_changed(self) 
        # この部分はObserverパターン。子が親に報告します。
        
        
class ErogeSystem(Mother): # 親の実装
    def __init__(self):
        self.__iincho = Heroine(u"いいんちょ")
        self.__akari = Heroine(u"あかり")
        self.__iincho.set_mother(self)
        self.__akari.set_mother(self)
    
    def child_changed(self, child): # 子に変更があった時(実装)
        print(u"changed {0}".format(child.name))
        
        if self.__iincho.likelevel > 90:
            # いいんちょはストーキングで攻略できるが
            self.__iincho.set_enabled(True)
        elif self.__iincho.likelevel > 50 and self.__akari.likelevel > 90:
            # あかりは他のキャラの好感度も高くないと攻略不可。
            self.__akari.set_enabled(True)
        else:
            pass
    
    @property
    def iincho(self): return self.__iincho
    
    @property
    def akari(self): return self.__akari

    
if __name__ == "__main__":
    system = ErogeSystem()
    for i in xrange(100): system.akari.likelevelup()
    for i in xrange(60): system.iincho.likelevelup()

[GoF]Observer パターンをpythonで書いてみた

Observerパターンをpython2.6で書いてみた。
なにかあったら全ての観察者に報告。


# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)


class Subject(object): # 報告する人(報告者)
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def set_observer(self, observer): # 観察者の場所を記憶(宣言)
        pass
            
    @abc.abstractmethod
    def notify(self, str): # 観察者に更新を報告(宣言)
        pass
        

class Observer(object): # 受信する人(観察者)
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def update(self, subject): # 子に変更があった時(宣言)
        pass


class Erogamer(Subject): # エロゲマ
    def __init__(self):
        self.__bbs = [] # 観察者一覧
        self.__kakiko = None # カキコ
    
    def set_observer(self, observer): # 観察者を記憶(実装)
        self.__bbs.append(observer)
    
    def notify(self, str):
        self.__kakiko = str        
        for o in self.__bbs:
            o.update(self)
    
    @property
    def kakiko(self): return self.__kakiko
        
        
class BBS2ch(Observer):
    def __init__(self, name):
        self.__name = name # 板名
        self.__log = []
    
    def update(self, subject): # 報告者に変更があった時(実装)
        self.__log.append(subject.kakiko) # 書き込みをログに保存
    
    @property
    def log(self): return self.__log

    
if __name__ == "__main__":
    eroge_otaku = Erogamer() # とあるオタ
    
    eroge_board = BBS2ch("エロゲ板")
    eroge_otaku.set_observer(eroge_board)
    
    negi_board = BBS2ch("葱板")
    eroge_otaku.set_observer(negi_board)
    
    eroge_otaku.notify(u"エロゲオタキモイ") # マルチポスト(・A・)イクナイ!
    
    for str in eroge_board.log: print(str)        
    for str in negi_board.log: print(str)

[GoF]Facadeパターンをpythonで書いてみた

Facadeパターンをpython2.6で書いてみた。
ゴチャゴチャした処理を、たった一つの関数にまとめます。

# -*- coding: utf-8 -*-

class BackgroundTask(object): # 裏画面処理
    
    def __init__(self):
        pass
        
    def draw_background(self): # 背景描画
        print(u"背景を描画しました。")
            
    def draw_charactor(self): # 立ち絵描画
        print(u"立ち絵を描画しました。")
            
    def draw_window(self): # メッセージウィンドウ描画
        print(u"メッセージウィンドウを描画しました。")
        
    def draw_string(self): # 文字列描画
        print(u"文字列を描画しました。")
        

class Screen(object): # 近所の店
    def __init__(self):
        pass
    
    def draw(self, is_h_scene=False):
        print(u"裏画面を確保しました。")
        
        bg = BackgroundTask()
        bg.draw_background()
        
        if not is_h_scene: # Hシーン中は、立ち絵必要なし。
            bg.draw_charactor()
        
        bg.draw_window()
        bg.draw_string()
        
        print(u"表画面に裏画面を上書きしました。")

        
if __name__ == "__main__":
#    is_h_scene = True
    is_h_scene = False
    Screen().draw(is_h_scene)

[GoF]Chain of Responsibilityパターンをpythonで書いてみた

Chain of Responsibilityパターンをpython2.6で書いてみた。
責任のたらい回し。こなせるなら自分で処理、ダメなら次の人に丸投げ。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class Shop(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod    
    def __init__(self):
        self.__nextshop = None # たらい回し先
    
    def set_next(self, nextshop):
        self.__nextshop = nextshop # 次の店を設定。
        return self # 数珠繋ぎにします(実はDecorator)
    
    @abc.abstractmethod    
    def has_eroge(self):
        pass
    
    def buy_eroge(self): # エロゲが欲しい
        if self.has_eroge(): # ハケーン
            return True      # good job!
        elif self.__nextshop != None: # 他に店がまだある
            return self.__nextshop.buy_eroge() # 他の店へGo
        else:                # 全部探したのに
            return False     # 見つからなかった…


class NearbyShop(Shop): # 近所の店
    def __init__(self):
        super(NearbyShop, self).__init__()
    
    def set_next(self, nextshop):
        return super(NearbyShop, self).set_next(nextshop)

    def has_eroge(self):
        return False

    def buy_eroge(self):
        print("NearbyShop")
        return super(NearbyShop, self).buy_eroge()


class Softmap(Shop): # ソフマップ
    def __init__(self):
        super(Softmap, self).__init__()
    
    def set_next(self, nextshop):
        return super(Softmap, self).set_next(nextshop)

    def has_eroge(self):
        return True

    def buy_eroge(self):
        print("Softmap")
        return super(Softmap, self).buy_eroge()


class Getchu(Shop): # げっちゅ屋
    def __init__(self):
        super(Getchu, self).__init__()
    
    def set_next(self, nextshop):
        return super(Getchu, self).set_next(nextshop)

    def has_eroge(self):
        return True

    def buy_eroge(self):
        print("Getchu")
        return super(Getchu, self).buy_eroge()


if __name__ == "__main__":
    route = NearbyShop().set_next(Softmap().set_next(Getchu()))    
    result = route.buy_eroge()
    
    # 近所の店は×だがソフマップは○。よって、巡回結果==true
    print(result)
    

[GoF]Visitorパターンをpythonで書いてみた

Visitorパターンをpython2.6で書いてみた。
それぞれの受入先での振る舞いを訪問者に集中させることで、処理と構造を分離。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class Visitor(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def visit(self, acceptor): # 問い合わせ(宣言)
        pass


class Acceptor(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def accept(self, visitor): # 問い合わせ(宣言)
        pass


class EHAShop(Acceptor): # 一般家電店
    def __init__(self):
        pass
    
    def accept(self, visitor):
        visitor.visit(self) # エロゲオタの問い合わせを実行


class ErogeShop(Acceptor): # エロゲショップ
    def __init__(self):
        pass
    
    def accept(self, visitor):
        visitor.visit(self) # エロゲオタの問い合わせを実行


class ErogeOtaku(Visitor): # エロゲオタ
    def __init__(self):
        self.__num_eroge = 0 # 所持エロゲ本数、最初は0
    
    def visit(self, shop): # 問い合わせ
        if isinstance(shop, ErogeShop): # メソッドオーバーロードの代わり
            print(u"エロゲゲット")
            self.__num_eroge += 1 # エロゲいっこ増やす
        else:
            print(u"エロゲが無くて(´・ω・`)ショボーン")
    
    @property
    def num_eroge(self):
        return self.__num_eroge


if __name__ == "__main__":
    kojima = EHAShop() # コジマ
    getchu = ErogeShop() # げっちゅ屋
    i = ErogeOtaku() # エロゲオタな漏れ
    
    getchu.accept(i)
    print(u"エロゲ所持数: {0} 本".format(i.num_eroge))    
    
    kojima.accept(i)
    print(u"エロゲ所持数: {0} 本".format(i.num_eroge))
    

[GoF]Decoratorパターンをpythonで書いてみた

Decoratorパターンをpython2.6で書いてみた。
引数と戻り値を同じ型にすると、飾りつけができます。

# -*- coding: utf-8 -*-

class Heroine(object): # ヒロイン
    def __init__(self):
        self.__equipments = [] # 身につけているもの
    
    def equip(self, equipment):
        self.__equipments.append(equipment)
    
    @property
    def equipments(self):
        return self.__equipments
    
    def clear_equipments(self):
        self.__equipments = []
    

def strip(heroine): # 裸にする
    heroine.clear_equipments()
    return heroine
    
def equip_headband(heroine): # カチューシャを着せる
    heroine.equip(u"カチューシャ")
    return heroine
    
def equip_kneesocks(heroine): # ニーソを着せる
    heroine.equip(u"ニーソ")
    return heroine

def equip_garterbelt(heroine): # ガーターベルトを着せる
    heroine.equip(u"ガーターベルト")
    return heroine

def equip_shorts(heroine): # ショーツを着せる
    heroine.equip(u"ショーツ")
    return heroine

def equip_brassiere(heroine): # ブラを着せる
    heroine.equip(u"ブラ")
    return heroine

def equip_shirt(heroine): # シャツを着せる
    heroine.equip(u"シャツ")
    return heroine

def equip_onepiecedress(heroine): # ワンピを着せる
    heroine.equip(u"ワンピ")
    return heroine

def equip_aprondress(heroine): # エプロンドレスを着せる
    heroine.equip(u"エプロンドレス")
    return heroine


if __name__ == "__main__":
    heroine = equip_aprondress(
        equip_onepiecedress(
            equip_shirt(
                equip_brassiere(
                    equip_shorts(
                        equip_garterbelt(
                            equip_kneesocks(
                                equip_headband(
                                    strip(Heroine())))))))))
    
    for equip in heroine.equipments:
        print(equip)
    
    print(u"メイドさんのできあがり")

[GoF]Compositeパターンをpythonで書いてみた

Compositeパターンをpython2.6で書いてみた。
ファイルとフォルダの関係のように、入れ物と中身を同一種として取り扱います。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class Item(object): # 入れ物と中身の共通クラス(宣言)
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def append(self, item): # 持ち物追加(宣言)
        pass


class Content(Item): # 中身クラス(アイテムを継承して実装)
    def __init__(self, name):
        self.__name = name
    
    def append(self, item): # 持ち物追加(中身ver)
        # 中身には何も追加できないので、なにもしません
        # 他に、例外をthrowして失敗を伝える方法もあります
        pass
    
    def __str__(self):
        return self.__name
        

class Container(Item): # 入れ物クラス(アイテムを継承して実装)
    def __init__(self, name):
        self.__name = name
        self.__list = []
    
    def append(self, item): # 持ち物追加(入れ物ver)
        self.__list.append(item)  # 一覧にアイテムを追加
    
    def __str__(self):
        return self.__name
    
    def __iter__(self):
        return iter(self.__list)
    

def print_item(item, indent):
    print(u"{1} +- {0}".format(item, indent))
    indent += "    "
    
    for i in item:
        if isinstance(i, Container):
            print_item(i, indent)
        elif isinstance(i, Content):
            print(u"{1} +- {0}".format(i, indent))
        else:
            print(u"{0} +- ".format(indent))

if __name__ == "__main__":
    case_box = Container(u"箱") # 箱
    cd_case = Container(u"CDケース") # CDケース
    game_cd = Content(u"ゲームCD") # ゲームCD
    manual = Content(u"マニュアル") # マニュアル
    quest_letter = Content(u"アンケートハガキ") # アンケートハガキ
    bear_pen = Content(u"くまシャーペン") # くまシャーペン
    
    case_box.append(cd_case)       # 箱 +- CDケース 
    cd_case.append(game_cd)        #   +- ゲームCD
    case_box.append(manual)        #   +- マニュアル
    case_box.append(quest_letter)  #   +- アンケートハガキ
    case_box.append(bear_pen)      #   +- くまシャーペン
    
    print_item(case_box, "")       # リストアップ(再帰を使うためメソッド化)

[GoF]Strategyパターンをpythonで書いてみた

Strategyパターンをpython2.6で書いてみた。
戦略部分を切り離すことで、動作をごっそり切り替えたりできます。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class SystemMode(object): # 戦略切換用の宣言集
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def menu(self): # メニュー宣言
        pass

    @abc.abstractmethod
    def complete(self): # ゲームクリア宣言
        pass


class NormalMode(SystemMode): # 製品用のメニュー
    def __init__(self):
        self.__iscompleted = False
    
    def menu(self): # 製品版では、CGモード=クリア後のお楽しみ。
        print(u"Enabled GamePlay") # ゲーム開始を選択可能にする
        
        if self.__iscompleted:
            # シナリオを1回クリアしていたら、CGモードオープン。
            print(u"Enabled CG Mode")
    
    def complete(self):
        self.__iscompleted = True
        

class DebugMode(SystemMode): # デバッグ用のメニュー
    def __init__(self):
        pass
    
    def menu(self): # デバッグ用なので、CGモードフルオープン。
        print(u"Enabled GamePlay")
        print(u"Enabled CG Mode")
    
    def complete(self):
        pass


class ErogeReleaseVerion(object): # エロゲ製品版
    def __init__(self): 
        self.__iscompleted = False # 1回クリアしたかどうかのフラグ
        self.__mode = NormalMode() # 製品版です
    
    def show_title(self): # タイトル画面の動作
        self.__mode.menu()         # 製品版なので通常モードのメニューを表示します
    
    def play(self): # 実際のゲーム
        print(u"ゲームでハァハァ")
        self.__mode.complete()
    
    def look_cg(self): # CGモード
        print(u"CGでハァハァ")
    

class ErogeDevVerion(object): # エロゲ開発版
    def __init__(self): 
        self.__iscompleted = False # 1回クリアしたかどうかのフラグ
        self.__mode = DebugMode() # 開発版なのでデバッグモード
    
    def show_title(self): # タイトル画面の動作
        self.__mode.menu()         # 開発版なのでデバッグモードのメニューを表示します
    
    def play(self): # 実際のゲーム
        print(u"ゲームでハァハァ")
        self.__mode.complete()
    
    def look_cg(self): # CGモード
        print(u"CGでハァハァ")
    

if __name__ == "__main__":
    game_ver = ErogeReleaseVerion()
#    game_ver = ErogeDevVerion()
    game_ver.show_title()
    game_ver.play()
    game_ver.show_title()
    game_ver.look_cg()
 

[GoF]Bridgeパターンをpythonで書いてみた

Bridgeパターンをpython2.6で書いてみた。
Factory系は、機能追加が苦手。(前述の例では、ヒロイン種の追加)
そこでBridgeパタンの登場。実装部を継承することでパワーアップさせます。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class Lolige(object): # ロリゲ必須要素を列挙
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def cosupure(self): # コスプレがあることを宣言
        pass

    @abc.abstractmethod
    def shiishii(self): # しーしーがあることを宣言
        pass
    

class Futago(Lolige): # 上記要素を実装
    def __init__(self):
        pass
    
    def cosupure(self): # コスプレを実装
        print(u"いろいろ")
        
    def shiishii(self): # しーしーを実装
        print(u"にょ")
    

class Hajirusu(object): # はじるす:ロリゲを核とするエロゲ
    def __init__(self, lolige): 
        self.__lolige = lolige # 核に双子要素をセット
    
    def cosupure_h(self): # コスプレイベントです。
        self.__lolige.cosupure()
    
    def shiishii_h(self): # しーしーイベントです。
        self.__lolige.shiishii()


# はじるすに「はじめて」がなかったことに非難轟々。
# そこで、はじいしゃには追加実装されることに。
class Hajiisha(Hajirusu): # 前作機能を再利用
    def __init__(self, lolige):
        super(Hajiisha, self).__init__(lolige) # はじるす版の初期化を行います。
    
    def cosupure_h(self): # 
        super(Hajiisha, self).cosupure_h()
    
    def shiishii_h(self): # 
        super(Hajiisha, self).shiishii_h()
    
    def hajimete_h(self): # 待望の追加機能
        print(u"ハカシーン")


if __name__ == "__main__":
    futago = Futago()
    
    hajirusu = Hajirusu(futago)
    hajirusu.cosupure_h()
    hajirusu.shiishii_h()
    
    hajiisha = Hajiisha(futago)
    hajiisha.cosupure_h()
    hajiisha.shiishii_h()
    hajiisha.hajimete_h()
    

[GoF]Builderパターンをpythonで書いてみた

Builderパターンをpython2.6で書いてみた。
複雑な構造は一気に作らず、少しずつ順番に。組立方法に従って、部品を組み立てます。

# -*- coding: utf-8 -*-

import abc # クラス抽象化を行うためのモジュール(requires python2.6 or later)

class Builder(object): # たくましくなる方法
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def doguts_at_sea(self): # 筋力up宣言その1
        # 海でガッツ
        pass # return muscle

    @abc.abstractmethod
    def doguts_at_mt(self): # 筋力up宣言その2
        # 山でガッツ
        pass # return muscle
    

class Muscle(object):
    def __init__(self, name):
        self.__name = name
    
    def __add__(self, muscle):
        return Muscle(u"{0} {1}".format(self.__name, str(muscle)))
    
    def __str__(self):
        return self.__name


class Hero(object): # 主人公クラス:筋力upを組立
    def __init__(self): 
        pass
    
    def doguts(self, heroine): # 鍛えます。
        muscle = Muscle(u"") 
        muscle += heroine.doguts_at_sea() # マッシヴ!
        muscle += heroine.doguts_at_mt() # モア マッシヴ!
        return muscle
    

class TakaSan(Builder): # 筋力up実装
    def __init__(self):
        pass
    
    def doguts_at_sea(self): # 筋力up宣言その1
        # 海でガッツ
        return Muscle(u"マッシヴ!!") # 実装その1

    def doguts_at_mt(self): # 筋力up宣言その2
        # 山でガッツ
        return Muscle(u"マッシヴ!!!!") # 実装その2


if __name__ == "__main__":
    muscle = Hero().doguts(heroine=TakaSan())
    print(muscle)