SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

よろずプログラマーのためのPython導入ガイド

Java meets Python - 第4回 配列と別れる50の方法(2) オセロゲーム

よろずプログラマーのためのPython導入ガイド (6)


デザインパターン:Null Object

 GoFのカタログにはない、古典的なパターンの一つがNull Objectです。

class Stone(GameItem):
    def __nonzero__(self): return True

class NullStone(Stone):
    def __nonzero__(self): return False

 クラスStoneは、オセロゲームの石を実現します。これには、面の状態(白/黒)を表すインスタンス属性stateが必要です。クラスNullStoneは、ゲーム開始するときに、眼に見えない石が置いてあるものと見なします。先の連載で紹介した事例(パズルゲーム/ライフゲーム)では、固有のメソッド定義を持つ、唯一の実体(soleinstance)として実現しました。ここでは、多数のインスタンスが必要なので、Stoneの子孫NullStoneとして実現します。

 先の連載で紹介したNull Objectは、盤面に石が置かれていない状態を表現するのに好都合で、これを特殊な石と見なします。つまり、白黒どちらの領地でもないマス目には「眼に見えない」特殊な石が存在します。これは、すべてのオブジェクトを平等に扱いつつ、その個性を尊重するという管理手法に適います。Null Objectに関する広範な論議は、Smalltalkが参考になります。

class Stone(GameItem):
    def paintItem(self, g):
        width = self.width(g)
        height = self.height(g)
        x = self.x * width
        y = self.y * height
        color = (Color.black, Color.white)[self.state]
        g.color = color
        g.fillOval(x, y, width, height)
        g.color = Color.black
        g.drawOval(x, y, width, height)

class NullStone(Stone):
    def paintItem(self, g): pass

 補助関数paintItemは、石を描きます。クラスStoneでは、その状態によって、黒 Color.green/白 Color.whiteの石を描きます。クラスNullStoneでは、何もする必要がないので、その本体は空passとなります。NullStoneを導入すると、Noneかどうかを判定する条件式が不要になるので、コードの見通しがよくなります。

sole instanceとしてのNull Object

nullStone = NullStone(None, None, None)

 同じ見えない石でも、どれとも異なるインスタンスnullStoneが、盤面の外に存在するものと見なします。このとき、インスタンス属性stateには、表裏(黒/白)どちらの状態でもない値Noneを設定すると共に、その座標x/yも未定義とします。

付記
 先に示した図はNull Objectの概念を表わしたもので、実際はsole objectとして実現されます。そのため、インスタンスnullStoneの実体(sole instance)は一つだけ存在しますが、あたかも盤面を取り囲むかのように図示してあります。

次にビューを

 次に、ビューに着手します。これは8×8のマス目を持つパネルとして実現します。

class GameBoardPanel(JPanel):
    def __init__(self):
        JPanel.__init__(self,
            mouseClicked=self.this_mouseClicked)
        self.initialize()
    def initialize(self):
        self.items = []
    def detect(self, x, y):
        obj = self.nullObject()
        for e in self.items:
            if e.isExist(x, y): obj = e; break
        return obj
    def paintItems(self, g):
        for e in self.items:
            e.paint(g)

 抽象クラスGameBoardPanelは、共通するプロトコルを規定します。ここで着目して欲しいのは、具象クラスを規定していないことです。組み込み型listや、インターフェイスShapeには依存しても、特定のクラスには依存しない「テンプレート」として機能します。すると、再利用性が高く、仕様の変更にも柔軟に対処できます。

 メソッド__init__は、ビュー(視覚部品)の特性を規定します。キーワード引数mouseClicked=には、イベントハンドラーとして、関数オブジェクトthis_mouseClickedを指定します。

 メソッドinitializeは、石をパネルに配置します。インスタンス属性itemsは、パネルに配置するすべての実体(インターフェイスShapeの規定を満たす任意のインスタンス)を保持します。

《Tips》開放閉鎖原則(OCP)
 親クラスでは、任意の実体を管理するコンテナーitemsだけを初期設定します。すると、仕様変更の影響を受けず、OCPにも準拠していることから、このモジュールを閉じる条件が整います。必要なら、その子孫クラスでinitializeを再定義しますが、このときに閉じた箇所をモジュールとして再利用するのが、約束事となっています。OCPに関する広範な論議は、Eiffelが参考になります。

 メソッドdetectは、指定した座標x/yを持つ実体を検出します。ただし、実際の処理は、インターフェイスShapeの規定を満たすインスタンスeに委ねます。最後に、その条件を満たす実体objをリターン値とします。

 メソッドpaintItemsは、バネルに配置したすべての実体を描画します。

class GameBoardPanel(JPanel):
    def nullObject(self):
        raise NotImplementedError, "def nullObject(self)"

class OthelloPanel(GameBoardPanel):
    def nullObject(self):
        return nullStone

 Null Objectパターンを活用するには、その対象となるオブジェクトが必要です。これを何にするかは、プロトコルに従って、メソッドnullObjectで指定します。クラスOthelloPanelでは、盤面の外を取り囲む特殊な石nullStoneをリターン値とします。

次のページ
理想的な作業机

この記事は参考になりましたか?

よろずプログラマーのためのPython導入ガイド連載記事一覧

もっと読む

この記事の著者

小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)

http://tamago-club.cocolog-nifty.com/「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたから楽ができるのと...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

伊藤うさぎ(イトウ ウサギ)

ペンネームの「由来は」と言うと。苗字の方は、セミナー研修で同じチームになった、3人の合体ユニット名 [I:石塚, T:田川, O:尾沢] から来ています。名前の方は、同じ干支(卯:1987 年生)に因んだものです。既に2人は卒業して、残る1人がその名跡を継承しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1802 2008/03/25 12:48

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー