[Jiemamy-dev:50] Re: [RFC] Collectionのアクセサメソッドについて

Back to archive index

MIYAMOTO Daisuke daisuke_m****@yahoo*****
2008年 6月 9日 (月) 02:44:12 JST


都元です。

Collectionのforループについてもう一つテーマを。
Mapもグルグルしたい時が多々ありますよね。しかもkey/value両方欲しかったり。
(片方であれば、Map#keySet() や Map#values() で普通に回せます)

そんな時、bacchusではこんな風にして回してました。

>>>
Map<String, Object> map = CollectionsUtil.newHashMap();
map.put("foo", new Foo());
map.put("bar", new Bar());

for(Map.Entry<String, Object> e : map.entrySet()) {
	String key = e.getKey();
	Object value = e.getValue();
	
	//...
}
<<<

これもList等の時と同様、Mapを返すメソッドに対して entrySet() でグルグル
する訳です。同じ理由で「普通にMapを返すメソッド」を書きたくない。

Listと共にこちらにも対処しなきゃいけないんです。
という事を思い出したので問題提起して、今日は寝ることにします。

おやすみなさいー。


2008/06/09 0:29 MIYAMOTO Daisuke <daisuke_m****@yahoo*****>:
> 都元でーす。
>
> 2008/06/08 22:41 Junichi Kato <j5ik2****@gmail*****>:
>> あ,とういか,第4案というより,すばり第3案ですねw
>
> あ、間違いw 第3案ですね。
>
> 2008/06/08 22:31 Junichi Kato <j5ik2****@gmail*****>:
>> public class Traversal {
> (中略)
>>        public Object forEachColumn(Table table, ColumnHandler handler) {
>>                for(Column column : table.getColumns()){
>>                        // 前処理
>>                        Object result = handler.processColumn(column.clone());
>>                        // 後処理
>>                        if (result != null){
>>                                return result;
>>                        }
>>                }
>>                return null;
>>        }
>>
>> }
>
> これって、Table#getColumns() を実装してますよね。
> これはどうやって回避しましょうか?
>
>
> 2008/06/08 23:23 NAGAYASU Yukinobu <nagay****@yukin*****>:
>> 見えます。前時代的って感じは特にしないなぁ、、、もしや私遅れてる?
>
> んーーー。Java界でJava5以降の人間なんですね、俺。
> 1.4時代を知らない。まだまだ1.4は現役だと思うので、そういう意味では
> Interatorも同様に現役だと思います。
>
> が、Java5以降ばっかり使っていると、実はIteratorってほぼ使わずに
> コードを上手く書けるんです。拡張for文を使って。
> 避けようと思えばまったくIteratorを使わないことだってできる。
> そういう意味で、Java1.4的なイメージですね、Iteratorは。
>
>>> >>> 案3 (ForEachHandler型)
>> これはキモいっす。Perl で似たようなことをやったんですが、自分でやっ
>> てて気持ち悪さが拭えませんでしたよ、えぇ orz
>
> そういう意見もあると思ってましたw
> が、加藤さん一押しであるように、「処理内容」をオブジェクト化する、というのは
> オブジェクト指向的な視点ではかなり親和性の高い考え方であるとも思います。
>
> これをキモいとすると、実はIteratorってのもキモくないですかw
> 今はパターンとして確固たる地位を確立しているから感じないだけで...
>
> というわけで、自分はキモさと分かりやすさの妥協点として第4案を推しましたが、
> 実は結構forEachも捨てがたいのではないかと考えてる感じです。
>
>> ところで 案2 か 案4 の場合についてなんですが、Iterable から返す
>> Iterator には remove() メソッドがあるんですけど、これの実装ってど
>> うしましょうね。
>
> そうですねぇ。仕様上も任意実装で、UnsupportedOperationExceptionが許されて
> いるので、使う機会が無いのであれば、その実装でもいいと思います。
>
> forで回しつつ、条件に一致するカラム(等)を削除する、って時に使うんかな〜。
>
> 2008/06/08 23:46 Junichi Kato <j5ik2****@gmail*****>:
>> まず,設計のポリシーとして,
>> クライアント側に自由度を与えるのか,与えないのか?
>
> そうですねー。俺個人としては、coreっていうのは
> 「Eclipseから使われ」、「Mavenから使われ」、もしかしたら我々の意図しない
> 「未知のクライアントからも使われ」るモノであると考えています。
>
> そういう意味では、意図せぬ使い方をされぬよう、結構カッチリ隠蔽して作った方が
> いいかな、と思ってるんですね。
>
>
> 2008/06/08 23:46 Junichi Kato <j5ik2****@gmail*****>:
>> 加藤です.
>>
>> お疲れ様です.
>>
>> まず,設計のポリシーとして,
>> クライアント側に自由度を与えるのか,与えないのか?
>> だとおもっていて,
>>
>> table.getColumns().add(xxx) はだめで
>> table.addColumn(xxx)にするという隠ぺい方針なんですが,
>>
>> table.getColumns()でforさせるというのは,逆にオープンになっているように
>> 思えるんですよね.
>>
>>
>> 値の参照系は,forやキーによる値の取得などの処理が考えられると思います
>> が,そのようなコードブロックを毎回クライアント側でしこしこ書くのは面倒だ
>> なぁと.
>> 面倒ならUtilityクラスに今回のようなforで検索するメソッド系をまとめると思
>> うので,それなら最初からforEachでいいかと思うんですよね.
>>
>> なので,
>>
>> table.addColumn(xxx);
>> table.removeColumn(xxx);
>> table.getColumn(columnKey);
>> table.forEachColumns(new ColumnHandler(){ });
>>
>> のほうが統一感あるなぁと.
>>
>>
>>
>>
>>> ところで 案2 か 案4 の場合についてなんですが、Iterable から返す
>>> Iterator には remove() メソッドがあるんですけど、これの実装ってど
>>> うしましょうね。
>>>
>>>   インタフェース Iterable<T>
>>>   http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/Iterable.html
>>>   インタフェース Iterator<E>
>>>   http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/Iterator.html
>>>
>>> ゆきのぶとしては、今回の目的(for したい)を考えるとあまり必要とい
>>> う感じもしないので、実装せずに UnsupportedOperationException を返
>>> すのが良いんじゃないかと思いました。
>>>
>>>
>>>> 都元です。
>>>>
>>>> コミットはまだしていませんが、一足先に、最低限必要なメソッドの実装を始めています。
>>>>
>>>> そこで迷っているのですが、Collection系のフィールドのaccessorメソッド(特にgetter)です。
>>>> 例えば、TableModelにはList<ColumnModel> columnsフィールドがあります。
>>>> このフィールドの直接のgetterを用意するのは、実装を公にし過ぎなんですよね。
>>>>
>>>> 地豆会でも指摘があった通り、TableModel#addColumn(column) では、変更を捕捉して
>>>> ChangeEventを飛ばす訳ですが、万一 getColumns().add(column) されてしまった場合、
>>>> 変更を検知することができません。
>>>>
>>>> というわけで、カラムの追加という観点では、columnsのgetterは使わず、addColumn
>>>> メソッドを用意する、ということになると思います。
>>>>
>>>> 次に、暫くすると「テーブルが持つカラムをforで回したい」という状況が頻繁に訪れます。
>>>> 従来ですと、これを実現する為に、getColumns() を用意し、
>>>>
>>>>
>>>>>>> 案1 (従来型)
>>>>>>>
>>>> ---- TableModel
>>>> public List<ColumnModel> getColumns() {
>>>>   return columns;
>>>> }
>>>> ---- client
>>>> for(ColumnModel column : table.getColumns()) {
>>>>   System.out.println(column.getName());
>>>> }
>>>> <<<
>>>>
>>>> というコードを書いていました。しかし、これが必要だからといってgetColumnsを用意して
>>>> しまうと、先の「getColumns().add(column)」を回避することができません。
>>>> bacchusでは「回避できないので、とりあえずやらないように気をつける」という
>>>> 対処を行って来ましたが、なんとかしたいもんです。
>>>>
>>>> 現在俺の頭にあるのは「columnsのイテレータを返すメソッドを作る」という手段と、
>>>> 前どこかで話が出た「forEachメソッドを作る」という手段です。
>>>>
>>>>
>>>>>>> 案2 (Iterator型)
>>>>>>>
>>>> ---- TableModel
>>>> public Iterator<ColumnModel> getColumnIterator() {
>>>>   return columns.iterator();
>>>> }
>>>> ---- client
>>>> Iterator<ColumnModel> itr = deptTable.getColumnIterator();
>>>> while(itr.hasNext()) {
>>>>   ColumnModel column = itr.next();
>>>>   System.out.println(column.getName());
>>>> }
>>>> <<<
>>>>
>>>>
>>>>>>> 案3 (ForEachHandler型)
>>>>>>>
>>>> ----
>>>> public interface ForEachHandler<T> {
>>>>   void handle(T model);
>>>> }
>>>> ---- TableModel
>>>>      public void forEach(ForEachHandler<ColumnModel> handler) {
>>>>              for (ColumnModel column : columns) {
>>>>                      handler.handle(column);
>>>>              }
>>>>      }
>>>> ---- client
>>>> deptTable.forEach(new ForEachHandler<ColumnModel>() {
>>>>   public void handle(ColumnModel column) {
>>>>     System.out.println(column.getName());
>>>>   }
>>>> });
>>>> <<<
>>>>
>>>>
>>>> しかし前者に関しては「なんかイテレータって前時代的じゃね?@@:」という
>>>> イメージがあったりします。もしかしたら、この意識間違ってる?(汗
>>>>
>>>> で、後者に関しては「キモくないですか? 大丈夫ですか?w」という危惧があります。
>>>> 安全性を確保できても、見通しが悪くなってしまうのでは採用の価値低いですからねぇ。。。
>>>>
>>>> この辺り、意見をまとめたいと思いますので、コメント下さい。
>>>>
>>>> と、ここまで書いて、良いアイデアが思いついた気がします。
>>>> getColumnsでList<ColumnModel>を返すからいけないんだ。
>>>>
>>>>
>>>>>>> 案4 (Iterable型)
>>>>>>>
>>>> ---- TableModel
>>>> public Iterable<ColumnModel> getColumns() {
>>>>   return columns;
>>>> }
>>>> ---- client
>>>> for(ColumnModel column : table.getColumns()) {
>>>>   System.out.println(column.getName());
>>>> }
>>>> <<<
>>>>
>>>> これならば、iterableにはadd出来ないので安全、かつ、見通しの良いforが書ける!
>>>> なんか結論出ちゃった気がしますがw みんなが見れば案4はキモいかもしれないw
>>>> ということで、一応ご意見ぼしゅー。
>>>>
>>>
>>>
>>
>> _______________________________________________
>> Jiemamy-dev mailing list
>> Jiema****@lists*****
>> http://lists.sourceforge.jp/mailman/listinfo/jiemamy-dev
>>
>
>
>
> --
> MIYAMOTO Daisuke
> skype: cuervo1800
>



-- 
MIYAMOTO Daisuke
skype: cuervo1800




Jiemamy-dev メーリングリストの案内
Back to archive index