- PR -

class or interface ?

投稿者投稿内容
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-09-01 13:49
引用:

よつもとさんの書き込み (2003-09-01 12:21) より:
引用:

オブジェクトを非常に多く使えるようにするためには, そのオブジェクトが
プロトコルを持たないようにすることが必要になると考えているんですけど
プロトコルはどうしても発生するものですから, それをオブジェクトの内部に
押し込めてしまって外部からは見えなくすればいいわけです.


ここで言うプロトコルとは、アルゴリズムのことでしょうか。
独自の用語は極力使わないか、どうしても必要なら日本語で解説してもらえると助かります。

こういう方法は、コードが分散しないという意味では一理あるのかもしれませんが、それは本質ではありません。むしろinterfaceが持つ良い意味での制約に影響を及ぼす、ダーティーな仕組みと考えています。
それを許すかどうかは改良というレベルではなく、Java言語の設計思想の見直しから考える必要がある論議ではないでしょうか。


乗り物の例で言うと, 乗り物を使って目的地につくためにはドライブだけでなくて
いろいろなメソッドをつかうわけです.
例えば現在位置を特定したり, また現在位置から目的地にいたるルートを特定したり
といったことです.
それらのメソッドを組み合わせて目的地に着くわけですが, そのメソッドを使う
手順のことをここではプロトコルと勝手に呼びました.
(ちょっと勝手にそう呼んでしまったのはまずかったかと思いますが)

このようなことが常にできるわけではありませんが, これもまたオブジェクト指向
と呼んで良い物と考えます.
現在のjavaの仕様とそれほどかけ離れたことを考えているわけではないと思います.
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2003-09-01 13:54
引用:

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

というように考えたらいかがでしょう



つまり、指示の受け渡しの関係は
運転手 <-> コンピュータ <-> 乗り物本体
のようになっているわけですよね。
運転手 <-> コンピュータ間は目的地の指示だけで、
コンピュータ <-> 乗り物本体間では実際のハンドル操作等のやり取りが行われると。

このように、問題領域(ドメイン)を抽象度や機能の固有性などをもとに分割することを
「レイヤリング」と呼び、分割された各部分を「レイヤ」と呼びます。
レイヤリングの基本は、あるレイヤに依存する対象を
隣接するレイヤに限定することです(レイヤリングにおけるカプセル化)。
すなわち、上の例で言うと、「運転手 <-> コンピュータ」と「コンピュータ <-> 乗り物本体」間の
やり取りの規約(=広い意味でのインターフェース)は独立していなければならないということです。

しかし、Junさんの例では、「運転手 <-> コンピュータ」のインターフェースがpublicメソッド、
「コンピュータ <-> 乗り物本体」のインターフェースが非publicメソッドとして混在することに
なってしまいます。
このようなやり方は、レイヤ間の独立性を大きく損ねるものだと思いませんか?

# ちなみに「レイヤリング」の失敗は、大抵の場合、大きな手戻りの発生や
# ソフトウェアの保守性の低下など、深刻な悪影響を引き起こします。

まとめると、
(1)interfaceに非publicなメンバの宣言も認める
メリット:
複数のレイヤ間の(広い意味での)インターフェースを一つのファイルに記述できる。
デメリット:
本来独立したものであるはずの複数のインターフェースを
一つの(Javaの)interfaceとして宣言することは、レイヤリングの原則に反する。

(2)interfaceにはpublicメンバしか認めない
メリット:
アクセス制限が一つしかないため、一つの(Javaの)interfaceに
一つの(レイヤ間)インターフェースを記述することが自ずと強制される。
デメリット(?):
レイヤリングの原則を無視するような記述ができない。

根拠は上に示したとおりです。


もしJunさんの意見が、
「レイヤリングやカプセル化の原則に反していようとも、
Javaのinterfaceに非publicなメンバを記述できる自由が
プログラマに与えられるべきだ」
というものでしたら、もはや私には反論する気はありません。
# でも、そういうのはC#とかでやってほしいなあ…

[ メッセージ編集済み 編集者: yamasa 編集日時 2003-09-02 15:28 ]
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-09-01 14:57
こんにちは。なんかJunさんの主張って変です。

:Javaのインターフェースのたとえ
電源アダプタとは、次のようなものである
1.形状が・・・・であること。
2.電圧や周波数が・・・・のとき、正しく動作すること。

:Junさんのインターフェースのたとえ
電源アダプタとは、次のようなものである
1.同上
2.同上
3.コンデンサはA社のものを使うこと
4.抵抗はB社のものを使うこと
5.電源安定化の部分はこの回路図を用いること
6.アースの部分はこの回路図を用いること

こういった内部のあれこれについて制約される規格は、だれも使わないと思います。

同様に、内部の実装方法について制約を受けるインターフェースも使いにくいと思います。もしこのようなインターフェースが存在すると、

class JPanel extends JComponent implements ImplementLikeThis1, ImplementLikeThis2 ..... ImplementLikeThis100

とかになって、内部実装の仕方を変更できなくなってしまいます。悲劇です。


[ メッセージ編集済み 編集者: ocean 編集日時 2003-09-01 15:02 ]
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-09-01 17:45
引用:

oceanさんの書き込み (2003-09-01 14:57) より:
こんにちは。なんかJunさんの主張って変です。

:Javaのインターフェースのたとえ
電源アダプタとは、次のようなものである
1.形状が・・・・であること。
2.電圧や周波数が・・・・のとき、正しく動作すること。

:Junさんのインターフェースのたとえ
電源アダプタとは、次のようなものである
1.同上
2.同上
3.コンデンサはA社のものを使うこと
4.抵抗はB社のものを使うこと
5.電源安定化の部分はこの回路図を用いること
6.アースの部分はこの回路図を用いること

こういった内部のあれこれについて制約される規格は、だれも使わないと思います。

同様に、内部の実装方法について制約を受けるインターフェースも使いにくいと思います。もしこのようなインターフェースが存在すると、

class JPanel extends JComponent implements ImplementLikeThis1, ImplementLikeThis2 ..... ImplementLikeThis100

とかになって、内部実装の仕方を変更できなくなってしまいます。悲劇です。


私の言っているのは全体で完結した(内部を意識することのない)クラスを提供しよう
ということであってその内部の構成については作成者側で把握しているのですから
それの制約を使用者側では意識する必要がないのです.
それを拡張して使うということは考えていないのです.
だから内部実装の仕方を変更できないのは悲劇でなく, それが目的だといっているのです.
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-09-01 18:16
引用:

それの制約を使用者側では意識する必要がないのです.



とのことですが、インターフェースは外部に公開されてしまっているので、

ImplementLikeThis1[] a = { new JPanel() };

といったコードが存在する場合、内部実装の変更(ImplementLikeThis1をやっぱりやめたとか)がコンパイルの失敗を招きます。ですので、使用者側でも意識せざるを得ません。java.util.RandomAccessはカテゴリを示す働きをしますが、Junさんのおっしゃるものとはやはり違う気がします。


[ メッセージ編集済み 編集者: ocean 編集日時 2003-09-01 18:36 ]
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-09-01 18:22
引用:

Junさんの書き込み (2003-09-01 17:45) より:
私の言っているのは全体で完結した(内部を意識することのない)クラスを提供しよう
ということであってその内部の構成については作成者側で把握しているのですから
それの制約を使用者側では意識する必要がないのです.
それを拡張して使うということは考えていないのです.
だから内部実装の仕方を変更できないのは悲劇でなく, それが目的だといっているのです.


つまり、あなたによるあなたのためのインターフェイスなのですね。
自分でインターフェイスを定義し、自分で実装クラスを作成する。
そして、インターフェイス型を他の人が参照することもない。

そういう目的ならば、package private(publicでない)インターフェイスと
実装クラスを定義することをお勧めします。

ちなみに、乗り物とコンピュータの例でコンピュータを乗り物(の実装クラス)の
サブクラスとして定義するのは、明らかにおかしいですよ。
A Computer is a kind of Vehicle.じゃないでしょ。
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-09-02 08:39
引用:

Wataさんの書き込み (2003-09-01 18:22) より:
引用:

Junさんの書き込み (2003-09-01 17:45) より:
私の言っているのは全体で完結した(内部を意識することのない)クラスを提供しよう
ということであってその内部の構成については作成者側で把握しているのですから
それの制約を使用者側では意識する必要がないのです.
それを拡張して使うということは考えていないのです.
だから内部実装の仕方を変更できないのは悲劇でなく, それが目的だといっているのです.


つまり、あなたによるあなたのためのインターフェイスなのですね。
自分でインターフェイスを定義し、自分で実装クラスを作成する。
そして、インターフェイス型を他の人が参照することもない。

そういう目的ならば、package private(publicでない)インターフェイスと
実装クラスを定義することをお勧めします。

ちなみに、乗り物とコンピュータの例でコンピュータを乗り物(の実装クラス)の
サブクラスとして定義するのは、明らかにおかしいですよ。
A Computer is a kind of Vehicle.じゃないでしょ。


コンピュータはサブクラスでなく私の例で言うとプロトコルに相当しますが
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-09-02 08:48
引用:

oceanさんの書き込み (2003-09-01 18:16) より:
引用:

それの制約を使用者側では意識する必要がないのです.



とのことですが、インターフェースは外部に公開されてしまっているので、

ImplementLikeThis1[] a = { new JPanel() };

といったコードが存在する場合、内部実装の変更(ImplementLikeThis1をやっぱりやめたとか)がコンパイルの失敗を招きます。ですので、使用者側でも意識せざるを得ません。java.util.RandomAccessはカテゴリを示す働きをしますが、Junさんのおっしゃるものとはやはり違う気がします。


[ メッセージ編集済み 編集者: ocean 編集日時 2003-09-01 18:36 ]


ですから本当はprotectedでなくprivateにしたいのだといったのです
でもprotectedでも出来上がったクラスをfinalにしてしまえばいいかな
と思っています.

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