- PR -

class or interface ?

投稿者投稿内容
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-08-29 12:53
引用:

Junさんの書き込み (2003-08-29 09:35) より:
ちょっと引用の仕方がわからないので引用しませんが, mRメソッドは呼び出さないの
です.mRメソッドを呼び出しているメソッドを呼び出すだけです.そのメソッドの内部では
mRメソッドが呼ばれています.mRメソッドは本来privateであるべきですが, そうすると
javaの現仕様ではオーバーライドできないのでprotectedにしてあります.publicよりまし
というに過ぎません.


では、interface RRは何のために存在しているのですか?
class AAA, BBBを使う側から見た場合、それらが
同じRR interfaceをimplementsしていることに何の意味があるのですか?

引用:

mR自身は外部から呼ばれないということです.
継承階層の内部のほかのpublicなメソッドから呼ばれます.


こういうのは「実装の詳細」と呼ばれ、クラスを使う側からは
隠蔽するのが大原則です(いわゆるカプセル化)。
しかし、Junさんの例ではこの実装の詳細が
"implements RR"という形で「漏れだして」います。

結局、Junさんの例は「カプセル化を壊すような記述ができないことは
Java言語の欠陥だ」と言っているのも同然のように私には感じられます。


# うわ、見事にかぶってしまった…

[ メッセージ編集済み 編集者: yamasa 編集日時 2003-08-29 12:55 ]
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-08-29 13:53
引用:

Junさんの書き込み (2003-08-29 09:39) より:
ちょっとStrategyというのを知らないのでできれば簡単な説明を付け加えてもらえるとありがたいです.


本屋に行けばデザインパターン本はたくさん見つかるので
ここでの解説は割愛します。
# 初学者なら結城さんの本( http://www.hyuki.com/dp/ )がお勧めです。

かわりにちょっと練習問題を。
コード:
public class Sample {
  public void doSomething() {
    /* 処理A */
    /* 処理B */
    /* 処理C */
    /* 処理D */
  }
}


上記のコードに、以下のような修正をしてみてください。

(a) 処理Bの内容を処理B'に切り替えて使うことができるようにしたい。
これを Template Method または Strategy パターンを使って実現せよ。

(b) (a)に加え、処理Cを処理C'や処理C''に切り替えて使えるようにしたい。
ただし、処理Bと処理Cはそれぞれ独立して切り替えられなければならない。
これを Template Method または Strategy パターンを使って実現せよ。


「委譲は手間がかかる」というのが単なる思い込みであることに気づくでしょう。
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-08-29 15:34
引用:

yamasaさんの書き込み (2003-08-29 12:53) より:
引用:

Junさんの書き込み (2003-08-29 09:35) より:
ちょっと引用の仕方がわからないので引用しませんが, mRメソッドは呼び出さないの
です.mRメソッドを呼び出しているメソッドを呼び出すだけです.そのメソッドの内部では
mRメソッドが呼ばれています.mRメソッドは本来privateであるべきですが, そうすると
javaの現仕様ではオーバーライドできないのでprotectedにしてあります.publicよりまし
というに過ぎません.


では、interface RRは何のために存在しているのですか?
class AAA, BBBを使う側から見た場合、それらが
同じRR interfaceをimplementsしていることに何の意味があるのですか?

引用:

mR自身は外部から呼ばれないということです.
継承階層の内部のほかのpublicなメソッドから呼ばれます.


こういうのは「実装の詳細」と呼ばれ、クラスを使う側からは
隠蔽するのが大原則です(いわゆるカプセル化)。
しかし、Junさんの例ではこの実装の詳細が
"implements RR"という形で「漏れだして」います。

結局、Junさんの例は「カプセル化を壊すような記述ができないことは
Java言語の欠陥だ」と言っているのも同然のように私には感じられます。


# うわ、見事にかぶってしまった…



いや, これは RR は概念的な一つの型であるといっているのです.mR はその型に属する
具象クラスで定義されるメソッドだけどそれは直接外部から呼んでほしくない
ただそのメソッドを使うプロトコルがあって, それはメソッドで定義されているから
そちらを呼んでくださいということです.

この例とは違うけど古臭い黴の生えたような例を持ち出しますが(オブジェクト指向
に関しては昔本を読んだことがあるだけで最近は読んでないので)
例えば乗り物をinterfaceとします
乗り物の具象クラスには車やバイクなどがあるとし, それらには走らせるという
メソッドや操作するための他のメソッドがあるとします.
これらのメソッドを使って乗り物を操作しても良いのですが面倒だからこんなことは
したくないと思って例えば次のようにします
乗り物にコンピュータを組み込み, そのコンピュータは目的を与えられれば勝手に
乗り物を操作し, 目的を達成してくれるのです.
こうなったら乗り物の操作を覚えている(=publicである)必要はありません.
その場合乗り物とは何か操作するメソッドがある(それはコンピュータにより必要
とされるメソッドであり何が必要か決まっているが(=interfaceにある) そのメソッド
は使えなくて良い(=publicでなくてよい))
どこかへいきたいときはプロトコルを指定する(=それらのメソッドをつかう別のメソッド
を呼ぶ)だけでよい

というように考えたらいかがでしょう
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-08-29 15:44
引用:

yamasaさんの書き込み (2003-08-28 15:23) より:
引用:

Junさんの書き込み (2003-08-28 14:07) より:

これがたくさんあったりまたRRのようなものを複数継承する
必要があるとしたら委譲を使わざるを得ないと思います.


委譲は「使わざるを得ない」ものでなく、むしろ
積極的に使うべきものだと私は思います。

そもそも、Junさんが挙げられた例は継承を使っている意味がないでしょう。
コード:
RR rr[] = 
{ 
new AAA(), 
new BBB(), 
};


この部分で、AAA, BBBのインスタンスをRR型の配列に入れて、何をするつもりなんですか?
RR型で唯一宣言されているmR()メソッドはprotectedなのでアクセスできませんし。


少し話を戻しますが、
引用:

Junさんの書き込み (2003-08-27 18:23) より:

これは手続き型プログラミングでいうとcallbackルーチンに相当する処理
(Cでいうと関数ポインタを使うような処理) に対して非常に有効です.
これらの処理をオブジェクト指向の多態性を利用した処理に置き換える場合
protectedなメソッド(本当はprivateであるべきだが, 残念ながらprivateなメソッドの
オーバーライドはjavaではできない.)がでてきます.


これはいわゆるTemplate Methodパターンですよね。
しかし、同様のことはStrategyパターンを用いてもできます。
こちらは委譲ベースのパターンなので、メソッドのアクセス制限を
意識する必要はありません。

Junさんの悩みも、Template MethodからStrategyへの置き換えをすれば
すぐに解決するものではないですか?



実現方法について悩んでいるわけではないのです.
私はデザインパターンについてはまったく知らないので(アンチパターンなら知ってるけど)
ちょつと内容が理解できませんが実現するだけなら方法はたくさんあるとは思います.

ただinterfaceでpublic属性以外が認められないということに意味を感じないので
それについていっているのです.
実現するにはどうしたらいいかということではありません

Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-08-29 15:56
引用:

ほむらさんの書き込み (2003-08-28 15:20) より:
ども、ほむらです。
間の抜けた質問をして申し訳ないのですが
JAVAでは上位のクラス(派生元)から下位のクラス(派生先)を
呼び出すことが出来るのですか?

提示していただいたソースはたとえprotectedが許されたとしても
かなり危険で、文法的にもあやしいプログラムだと思うのですが。。。
今のところの僕の知識ではinterface の mR()を呼び出すための手順が思い浮かびません

それと明記はされていませんが class AAとclass BBを宣言する時点で
RR_Baseみたいなクラスを継承する形ではいけないのでしょうか?
class AA extends RR_Base
class BB extends RR_Base
みたいな




protectedについては何回かいってますがこれは上位からも呼び出さないので
本質的にはprivateでよいはずです
ただjavaの仕様ではprivateなメソッドはオーバーライドできないので
protectedにしてあります.
またRというクラスは元々継承するだけでRRのinterfaceを使えるようにするための
クラスですがもし別なクラスを継承する必要があったとき(つまり多重継承になる場合)に
そのようなクラスは継承できないという意味で書いたのです
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-08-29 17:27
ども、ほむらです。
-------------
Jun氏へ
引用:
コード:

interface RR
{
protected abstract void mR();
}
public abstract class A extends AA implements RR
{
public void m(int i){mR();...}
}



呼び出せないといったのはこの部分です。
あとで個人的にabstractの記述は省略しただけかなと理由つけていますが。。。
この状態では class A からでも mR()は呼び出せないように思えます。

引用:

protectedについては何回かいってますがこれは上位からも呼び出さないので
本質的にはprivateでよいはずです
ただjavaの仕様ではprivateなメソッドはオーバーライドできないので
protectedにしてあります


以前から気になっていたのですが。。。。
privateなメンバをオーバーライドできないのはJavaの仕様でなく
カプセル化という性質の問題です。
protected と private の違いを気にした上で
もし、privateだったらオーバーライドできるのかということを
考えてみてください。
見えないのでオーバーライドできないはずです。

もうひとつ、別の方へのレスでしたが言わせてください。
引用:

例えば乗り物をinterfaceとします
乗り物の具象クラスには車やバイクなどがあるとし, それらには走らせるという
メソッドや操作するための他のメソッドがあるとします.
これらのメソッドを使って乗り物を操作しても良いのですが面倒だからこんなことは
したくないと思って例えば次のようにします
乗り物にコンピュータを組み込み, そのコンピュータは目的を与えられれば勝手に
乗り物を操作し, 目的を達成してくれるのです.
こうなったら乗り物の操作を覚えている(=publicである)必要はありません.
その場合乗り物とは何か操作するメソッドがある(それはコンピュータにより必要
とされるメソッドであり何が必要か決まっているが(=interfaceにある) そのメソッド
は使えなくて良い(=publicでなくてよい))
どこかへいきたいときはプロトコルを指定する(=それらのメソッドをつかう別のメソッド
を呼ぶ)だけでよい


ここでいうコンピュータの動作はclassであるべきだと思います。
デザインパターンで言うとStrategyパターンというやつになるのかな?

僕が思うにコンピュータがインターフェイスであるのならば
このコンピュータは乗り物だけでなく動物やロボットにも適用できるものでなければ
ならないはずです。

なんていうか。。インターフェイスというならば
コンピュータが乗り物を操作するのではなく
乗り物がコンピュータを操作できなければならないと思うのです。

# 追伸
# なんか、オブジェクトに対するものの考え方が反対かな〜なんて気がしてきた。

# 追伸を追加


[ メッセージ編集済み 編集者: ほむら 編集日時 2003-08-29 17:32 ]
酒樽
会議室デビュー日: 2002/06/06
投稿数: 10
投稿日時: 2003-08-29 17:50
引用:

Junさんの書き込み (2003-08-29 15:34) より:
いや, これは RR は概念的な一つの型であるといっているのです.mR はその型に属する
具象クラスで定義されるメソッドだけどそれは直接外部から呼んでほしくない
ただそのメソッドを使うプロトコルがあって, それはメソッドで定義されているから
そちらを呼んでくださいということです.


結局、interfaceであるRRの中で「mRのメソッドを呼び出しなさい」という暗黙の強制をしていることになりますね。
引用:

例えば乗り物をinterfaceとします
乗り物の具象クラスには車やバイクなどがあるとし, それらには走らせるという
メソッドや操作するための他のメソッドがあるとします.
これらのメソッドを使って乗り物を操作しても良いのですが面倒だからこんなことは
したくないと思って例えば次のようにします
乗り物にコンピュータを組み込み, そのコンピュータは目的を与えられれば勝手に
乗り物を操作し, 目的を達成してくれるのです.
こうなったら乗り物の操作を覚えている(=publicである)必要はありません.


この場合、外部から見えるのは「乗り物は自動動作する」ということだけです。
隠蔽されているのは実装そのものではないかも知れませんが、設計図にあたるものだと考えられます。
しかし、interfaceはあくまで入出力の規格("プロトコル"というと解釈が幅広いので、規格に置き換えました)を規定するものなので、設計図であっても含むべきではないと思います。
実装者にヒントを提示する用途であれば、mRをライブラリとして外に出して、ドキュメントで誘導するのが妥当でしょう。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-08-29 17:56
引用:

例えば乗り物をinterfaceとします
乗り物の具象クラスには車やバイクなどがあるとし, それらには走らせるという
メソッドや操作するための他のメソッドがあるとします.
これらのメソッドを使って乗り物を操作しても良いのですが面倒だからこんなことは
したくないと思って例えば次のようにします
乗り物にコンピュータを組み込み, そのコンピュータは目的を与えられれば勝手に
乗り物を操作し, 目的を達成してくれるのです.
こうなったら乗り物の操作を覚えている(=publicである)必要はありません.
その場合乗り物とは何か操作するメソッドがある(それはコンピュータにより必要
とされるメソッドであり何が必要か決まっているが(=interfaceにある) そのメソッド
は使えなくて良い(=publicでなくてよい))



以下の様なコードが自然だと思うのですが。もちろんinterfaceにはprotectedなメソッドを必要としません。
コード:
interface Vehicle {
	public void drive();
	public void setDriver(Driver inDriver);
}

interface Driver {
	public void drive();
}

class Car implements Vehicle {
	Driver mDriver;
	
	public Car() {
		mDriver = new ComputerDriver();
	}
	
	public void setDriver(Driver inDriver) {
		mDriver = inDriver;
	}
	
	public void drive() {
		mDriver.drive();
	}
}

class HumanDriver implements Driver {
	public void drive() {
		...
	}
}

class ComputerDriver implements Driver {
	public void drive() {
		...
	}
}

public class Main {
	public static void main(String inArgs[]) {
		Vehicle aVehicle = new Car();
		
		aVehicle.drive(); // こんぴゅーたー様が車を運転
		
		aVehicle.setDriver(new HumanDriver());
		aVehicle.drive(); // 一市民が車を運転
	}
}

スキルアップ/キャリアアップ(JOB@IT)