《余録》継承の隘路 - 継承は必要悪か

Java プログラマーのための Python 導入ガイド記事一覧
《余録》 継承の隘路 - 継承は必要悪か

《著》小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2003/05/23 ● 第2版♪2009/04/03

■ 概要

特殊メソッド __getattribute__ を利用すると、「継承の問題点」を回避する、新たな方策が可能になります。

 OOP の黎明期には脚光を浴びた継承も、やがて、さまざまな問題点が指摘されることになります。
 その反省から、継承から委譲へとパラダイムシフトが起こりますが、では継承は「必要悪」なのでしょうか。
 継承は「必要悪」委譲は「救世主」とするステレオタイプには「再」再考の余地があります。

 《Note》JPython1.1.x/Jython2.1.x 用に作成したセミナー課題を、Jython2.5 で再構成しました。
■ 関連記事
参考文献 note
JavaプログラマのためのUML活用ガイド―例題に学ぶオブジェクト指向プログラミング設計

JavaプログラマのためのUML活用ガイド―例題に学ぶオブジェクト指向プログラミング設計

「継承」の問題を回避するために「委譲」を活用する方法を紹介しています。

背景

Python 2.3 以降になると、新たなクラス体系を支援する、特別なメソッド __getattribute__ を利用できます。すると「継承の問題点」を回避する、新たな方策が可能になります。そこで、今回は「委譲」が抱える問題を回避するために、再び「継承」を取り上げることで、継承の本質に原点回帰します。

OOP の黎明期(1970 年代)には「継承」はそれを支える三本柱のひとつとして脚光を浴びました。
しかし、技術的には未成熟な部分が多く、1980 年代になると、その問題点が指摘されるようになります。
スリーアミーゴのひとり(後に UML に強く影響を与える)Rumbaugh さんの著書(1991 年)でも
「継承の問題点」が指摘されるなど、継承に「警鐘を鳴らす」いくつかの論文が発表されます。
1990 年代になると、継承の問題を回避する救世主として「委譲」へのパラダイムシフトが広く認知されるようになりました。
デザインパターン」が一般にも認知される契機となった、GoF の著書(1995 年)にも、その問題を回避する手法が紹介されています。
同じ年に発表された Java を初め、その後の C# など、新たに考案された OOP 言語が、
継承に代わる委譲を強力に支援することで、差別化を図るかのように進化していったという歴史があります。
そして、Python/Ruby など、より本格的な OOP 言語が普及し始めると、Java/C# にはない強力な支援機能によって、
再び継承の持つ本来の意義が見直されています。

歴史は繰り返すという言葉があります。
技術の進歩が価値観を一変させ、一度否定されれた技術が再び脚光を浴びるなどは、歴史を紐解くまでもありません。

Python の強力な支援機能を利用して「継承」の問題点を回避する方法について再考します。

⇔ 承前 何が問題だった のか:継承に継承を鳴らす
⇔ 承前 何が問題だった のか:継承が抱える深刻な問題
⇔ 承前 何が問題だった のか:委譲による問題回避

事例:スタックを実現する

組み込み型 list の動作を「継承」によって、自由に拡張/抑制できます。そこで、list の機能を再利用するとともに、スタックを実現するのに必要のない機能はすべて無効にします。

■ 機能の抑制

特殊なメソッド __getattribute__ は、任意の属性へのアクセスを横取りして、ドット「.」による値の参照/変更、メソッド呼び出しなどを自由に制御できます。

class Stack(list):
    def __getattribute__(self, name):
        dirs = {
            "push": "append",
            "pop" : "pop"   ,
        }
        name = dirs.get(name)
        if not name:
            raise AttributeError
        return list.__getattribute__(self, name)

クラス Stack は、組み込み型 list を継承したにも関わらず、メソッド push/pop 以外をすべて無効にします。メソッド push は、既存のメソッド append を再利用します。また、メソッド pop は、既存のメソッド pop の動作を、次のように変更します。

■ 機能の拡張(変更)

継承によって、既存のメソッドの動作を自由に拡張できます。

    def pop(self):
        try:
            return list.pop(self)
        except:
            return None

メソッド pop は(組み込み型 list とは違って)空のリストに対して例外を生成せずに、None をリターン値にします。

⇒ 続きはこちら 《余録》継承は必要悪か __getattribute__

Tips

Java プログラマーにとっての朗報は、Jython を導入することで、継承の問題を回避できる可能性が広がることです。
》作業中です《

Last updated♪09/06/02