ひしだまの変更履歴

ひしだまHPの更新履歴。
主にTRPGリプレイの元ネタ集、プログラミング技術メモと自作ソフト、好きなゲームや音楽です。

比喩でJavaのオブジェクト指向を説明してみる

2012-05-16 22:40:12 | PG(Java)

オブジェクト指向の説明をするのに色々な比喩が用いられ(、実際のプログラミングと離れていて結局分かりにくいと批判され)ているが、敢えて例えてみたい。


例として、政党を考えてみる。(以下、政党名や変数名はてきとーに架空のものを使用)

まず、共通のものとして「政党」を定義する。Javaで書くとこんな感じ。

public interface 政党 {
  public abstract 政策 政策を作成する();
}

「政策を作成する」というメソッドを持つインターフェースである。
インターフェースは「こういう処理を呼び出せる」というメソッド一覧を定義するもの。
実際の処理(ここでは「政策の中身」)は規定せず、「政党であれば政策を作成する機能を持つ」ということだけを定義している。
abstractは「抽象」と訳されている。実際の処理を書かないメソッドは抽象メソッドと呼ばれる。
(なお、インターフェースの抽象メソッドではabstractキーワードは省略することが出来る)
(抽象メソッドを持つクラスは抽象クラスと呼ばれる。インターフェースは特殊な抽象クラスとも言える) 

このようにしておくと、例えば政策を実施する官僚クラスからは以下のような感じで政党から政策を取得することが出来る。

private class 官僚 {
  public 結果 政策を実施する(政党 s) {
    try {
      政策 dummy =  s.政策を作成する();
    } catch(Exception e) {
    }
    return new 天下り先();
  }
}

実体がどの政党であるかに関わらず、メソッドを呼び出すように記述できる。これがオブジェクト指向(インターフェースを用いたプログラミング)の優れた点である。

なお、try~catchは例外(正常な結果でない出来事)が起きたときにそれを受け止めて何らかの処理を行う為のもの。今回はcatch句に何も書いていないが、こういうのは「例外を握り潰す」と言われ、良くないコーディングの典型である。(例外は「都合の悪い事」ではなく「発生しうる事」なので、それに応じた処理を行う必要がある。少なくとも、ログ出力などを行い、外部の人(運用者)に見えるようにすべきである)


そして、実際の個々の政党クラスは“政党インターフェース”を実装することになる。「実装」とは、具体的な処理を記述することである。
(具体的に処理が書かれているクラスを、(抽象クラスに対して)具象(ぐしょう)クラスと呼ぶ) 

例えば「自分が良ければ他人や将来の世代のことなんかどうでもいい党(以下、自党)」や「共に生産性を上げようなどと人類には不可能なことを言う党(以下、共党)」は以下のように書ける。

public class 自党 implements 政党 {
  @Override
  public 政策 政策を作成する() {
    return new 我田引鉄();
  }
}

public class 共党 implements 政党 {
  @Override
  public 政策 政策を作成する() {
    return new 実現不可能な理想論();
  }

継承元クラスに存在するメソッドに自分の処理を記述することを「オーバーライド(上書き)する」と言う。オーバーライドされたメソッドには@Overrideというアノテーションを付ける。

クラスの定義は、処理内容が記述されているだけであり、プログラム内で使う際には「インスタンス」を作る必要がある。インスタンスとは、いわば「処理を行う“中の人”」である。

インスタンスは「new」を使って作成する。以下の様になる。

政党 元祖自党 = new 自党();
政党 亀下新党 = new 自党();
政党 石井新党 = new 自党();
政党 橋原新党 = new 自党();

これらは、インスタンス(中の人)は違うが、クラスは同じなので実施する処理内容も全く同じである。

なお、変数の宣言は、実際のクラス名でなく、インターフェース名ですべき。そうすれば、後からnewするクラスをとっかえひっかえしても後続のプログラムは影響を受けない。


既存のクラスを継承して新しいクラスを作ることも出来る。
例えば、自党を継承した「民の為と称して好き勝手やる党(以下、民党)」は以下の様になる。

public class 民党 extends 自党 {
}

継承元と処理が同じ場合は、特に処理(メソッド)を書く必要は無い。

政党 小沢自党 = new 民党();


他の具象クラスを直接継承(extends)するのではなく、別インスタンスのメソッドを呼び出すような構造も作れる。
こういう仕組みを「委譲」と言う。

public class 委譲政党 extends 政党 {
  protected 政党 s;
  public 委譲政党(政党 s) { //コンストラクター
    this.s = s;
  }
  @Override
  public 政策 政策を作成する() {
    return s.政策を作成する(); //他の政党に委譲する(他の政党の政策をそのまま使う)
  }
}

コンストラクターは、インスタンスを作る際に引数を受け取ったりそのクラス独自の初期化を行ったりするもの。
コンストラクターで引数を受け取ってフィールド(クラス内で共通に使える変数)に保持するのは常套手段。
フィールド(「フィールド変数」という呼び方は間違い)とローカル変数で同じ変数名を使うことが出来る。同じ場所で使う場合、区別できるよう、フィールドには「this.」を付ける。
(同じ名前を付けることによって別変数にアクセスできなくなることをシャドーイングと言う) 

引数つきのコンストラクターを使ってインスタンスを作る場合は、newするときに引数を渡す必要がある。 

政党 公党 = new 委譲政党(元祖自党);
政党 社党 = new 委譲政党(元祖自党);


全然関係ないですが、つい最近、虚構新聞に釣られる人が出て話題になってましたね。
自分も虚構新聞には何度か騙されて^^;楽しませていただいていますがw、情報が正しいのか、どういう意図で書かれているのか・信じるのかは読み手が汲み取れるようにならないといけませんね。騙そうとする人(宗教や新聞テレビのプロパガンダ等)は、「嘘」と書かずに嘘をついたり誘導したりするので。(虚構新聞は虚構と書いてくれているので良心的w)
それがネットリテラシー、いやネットに限らずリテラシーとして必要なんでしょう、現代人には。
騙す方が悪いとは思いますが、犯罪者に倫理観を求めるのは不可能なので。