ページ

2014年8月20日

保土ヶ谷のジムとか

ほっといたら、だんだん書かなくなるので…

で、平塚から横浜の保土ヶ谷に引っ越して数カ月がたちました。平塚にいたころは、セントラルのフィットネスクラブか市のトレーニングルームに行っていました。まあ、市のトレーニングルームはちょっと遠かったので、セントラルが休みの時とか、数えるほどしか行ってませんが…

で、保土ヶ谷に引っ越して、近くにジムはいくつかあります。健康保険の福利厚生で利用できるのは天王町のコナミです。でも、ここ、狭い!まあ、狭いのはいいです。マシンが古い。使えなくもないのですが、狭い上にボロっちいマシンだとモチベーションが上がらないし、なんだか、筋トレコーナーが済に追いやられている感じがしてちょっと・・・。でも、スタッフのおねーさんは可愛かった。でも、一回行っただけで行くのをやめました。横浜のコナミは高いので無理です。

そのあと、保土ヶ谷区のスポーツセンター(横浜市のやつ)にしばらく、行っていました。一回300円でリーズナブルですが、それなりに混んでいます。 トレッドミルは結構使われていて、空くのをじっと待つのです。フリーウェイトのコーナーは強うそうな人たちが独占してます。あんなところ、怖くて入っていけません。まあ、そもそも、フリーウェイトのコーナーに入るには講習を受けないと行けないらしいですが、めんどくさくて受けてません。なので、あそこに入る資格すらありません。マシンは去年、入れ替えたばかりなので、どれも新しくて綺麗です。

で、そんなこんなで、もうちょっとジムにちゃんと行きたいな〜、って思って、駅ビルにあるJexerに行ったんですよ。見学に行った時、潰れるんじゃないかってぐらい、空いてるんです。いいですね。基本的に空いていて、混む時間帯でもそれなりみたいです。経営する方は大変かもしれませんが、利用する方はいいですね。2ヶ月ちょっと通っていますが、ほとんど順番待ちをすることがないです。有酸素系は全く待たないです。利用人数に対して有酸素マシンの数が多すぎます(笑)。

でも、ちょっと狭い。でも、狭すぎることはないです。で、筋トレと有酸素運動しかできません。プールはないし、スタジオもないです。プールもスタジオもどちらも使わないので、それらがない分、安いのはいいです。えーと、月5000円ぐらいです。あと、サウナは欲しい…。かも。

でもって、スタッフの人も暇なのか、いろいろ話しかけて来てくれるので、いい感じです。いや、最初は黙々とやれればいいと思っていたので、うっとおしかったです。でも、フォームがおかしかったらこちらから言わなくても教えてくれるし、何かを発見しても教えてくれるし、いい感じです。ただ、他の人に教えているのを見ていると、他の人には最初は軽い重量で教えているのに、僕には普通の重量を与えられます。

で、全体的に空いていて、フリーウェイトのところにも、とっても強うそうな人はいません。平塚のジムはバーベルに人がいると数十分ぐらい専有し続けていました、ここはそんなに長時間専有し続ける人がいないです。まあ、フリーウェイトはちょっと混み気味と時もありますが、そんな時も少し待てば使えます。

それと、スタッフの人は休憩時間とか仕事が終わったら、一緒にトレーニングしています。いいですね。

あっ、あと、このジム、社員のひとは人の名前をちゃんと覚えています。バイトの人はよくわからないですが・・・。普通に○○さん、って呼びかけてきます。
あと、3日行かないと、「久しぶりですね」って言われます…。

2014年4月1日

拡張forループでループの回数も同時に欲しいよね、でこんなふうに書いた

昨日のアリエルであったJava8の勉強会で、iteratorをそのままstreamに流せないと初めて知って、いささかめんどくさい感があったりもしますが、世の中、そんなものです。あったかくなってきたとか、朝が夜ではなく朝になってきたとか、桜が咲いたとか、浮かれている場合ではありません。

前回、iterator自分で書いてみない?ってことで、だれも書いてくれなくってとても残念です。なので、自分で書いてみました。

import java.util.*;

public class CollectionUtil {
    public static class Entry<T> {
         int index;
         T value;
         Entry(int index, T value) {
             this.index = index;
             this.value = value;
         }

         public int getIndex() { return index; }
         public T getValue() { return value; }

    }

    public static <T> Iterable<Entry<T>> enumurate(Iterable<T> iterable) {
        final Iterator<T> iter = iterable.iterator();
        return new Iterable<Entry<T>>() {
            public Iterator<Entry<T>> iterator() {
                return new Iterator<Entry<T>>() {
                    int index = 0;
                    public boolean hasNext() {
                        return iter.hasNext();
                    }
           
                    public void remove() {
                        iter.remove();
                    }

                    public Entry<T> next() {
                        return new  Entry<T>(index++, iter.next());
                    }
                };
            }
        };
    }


    public static void main(String[] argv) {
        List<String> l = new ArrayList<String>();
        l.add("hoge");
        l.add("fuga");
        for (Entry<String> entry: CollectionUtil.<String>enumurate(l)) {
             int index = entry.getIndex();
             String v = entry.getValue();
             System.out.println(index + " " + v);
        }
    }
}

色がついていないと、ちょっと読みにくいですね。IDEにでも貼り付けて、綺麗にしてください。

で、僕はPythonista(Pythonを使う人)だったらしいので、enumurateってメソッドを作ってあげて、その人がiterableのオブジェクトを返すことにしてあげました。やっていることは基本的には同じです。なんとかクラスを実装してください、って課題なのに、設問をいきなり無視しています。年寄りはそんなものです。我慢してください。

この手のメソッドを作るときによくやるのが、引数とかで本当の具象クラスを指定することはさすがにないと思いますが、ListやCollectionを指定しちゃうことが多いです。enumurateの中身は引数からiteratorが取れればいいだけなので、Itarableインターフェースを指定します。曖昧にできるところはなるべく曖昧にしておいたほうが、メソッドがいろいろ使いまわせてよいのです。



無名クラス、いっぱい。なぜ、無名クラスにしたのかって言うと、クラス名を何にするか決められなったからです。

Iteratorは、Javaに限らず一般的なプログラミングの概念です。気になる人は、パーフェクトJavaの181ページを読んでください。あれ?無名クラスについては書いていない気がする。井上さん、追加してください。それから、マルチスレッド的なことも、Concurrentを追加してください。その代わりにGUIの部分はなくてもいいです。
それから、enumはやれば出来る子なので、もっと詳しくして欲しいです。

DaoでのResultSetへのアクセスはenumでいいよね

Java8でラムダが使えれば…。
で、DaoでResultSetへのアクセスでインデックスでアクセスする場合、

int index=0;

dto.setX(resultSet.getInt(++index);
dto.setY(resultSet.getInt(++index);
dto.setZ(resultSet.getInt(++index);

ってアクセスさせるとメンテナンス性が落ちるよね、って話しでした。個人的にはカラムでのアクセスで問題ないと思っていますが、インデックスでのアクセスもenumでアクセスさせれば、もう少し、メンテナンス性が上がります。

こんなかんじですね。

enum ColumnName  {
    column1,
    column2,
    column3;

    public int getIndex() {
        return ordinal() + 1;
    }

    public static String getSelectStatement() {
        StringBuilder sb = new StringBuilder();
        for (String s: ColumnName.values()) {
            if (sb.length()>0) {
                 sb.append(",")
             }
             sb.append(s):
          }
     }
}


SQL文を組み立てるときは


    String sql = "SELECT " + ColumnName.getSelectStatetement() + " FROM SOME_TABLE"

ResultSetは、

    dto.setX(rs.getInt(ColumnName.column1));
    dto.setY(rs.getInt(ColumnName.column2));
    dto.setZ(rs.getInt(ColumnName.column3));

ほら。フィールドが追加されてもenumに値をセットするだけで、順番も意識しなくてよくなりました。

まあ、enumに値を追加することに神経を集中してdtoに詰めるのを忘れちゃいそうですね。

で、これがもう少しメンテナンス性は挙げられるようになる、と書いていた理由です。
ということで、技術は楽をするための道具です。言語に新しく追加されたものは、世界中の頭のいい人が、もっと楽をしたいと思って追加されるものです。なので、マゾな人以外は積極的に新しいものを使って、楽をできるところは楽をして、本質的に難しいところに開発者は専念すべきなのです。そのために、新しい技術を追い求めるのです。いやいや、それは嘘です。僕は新しいものが好きだから、追い求めるだけです。


それから、そのうち、リフレクションしたくなってくるかもしれません。でも、それすると、メンテナンス性が更に高まりますが、パフォーマンスは少し落ちます。我慢してください。その次がバイトコード生成ですが、そこまで行くと、もう、あちらの世界の住人になって、もう、戻ってこれません。気をつけてください。

追記
======

最近は朝、家を出る時が夜ではなく朝になってきて、ちょっと嬉しいです。

ということで、昨日の続き。昨日のように慌ただしいタイミングじゃないのでゆっくりと書けます。

まず、前提としてenumはやれば出来る子です。どこかでenumは所詮はクラスだよ、と書いたつもりですが、所詮はクラスなので、クラスでできることは大体出来ます。Effective Javaにはシングルトンもenumでできるよ、って書いていたように思いますが、僕は実際にやったことはないです。

さて、所詮はクラス、されどクラスなので、enumもinterfaceを身にまとってかっこ良く振る舞ってくれます。
例えばこんな感じ。

interface Ge {
    public void urya();
}

enum Ho implements Ho {
    H {
        public void urya() { System.out.println("Hoo"); }
    },
    G {
        public void urya() { System.out.println("Gee"); }
    }
}

で、 Ho.H.urya()って感じで使えます。なので、

for (Ho h: Ho.values) {
    h.urya();
}

で全部回りますね。


じゃあ、本題です。Daoでdtoにブツを詰め込むときに、場所が離れていると詰めるのを忘れがちになります。頑張ればHibernateがやっているようにもっとスマートにできなくもないですが、それならHibernate使えよ、ということになってしまいます。なので、現実的な妥協点は次のような感じ。
変数名とかメソッド名は割と適当なので、適当に置き換えてください。。


interface Binder {
    public void bind(int position, ResultSet rs, Dto dto);
}

enum Column implements Binder {
    FIELD_A {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_A(rs.getInt(position + 1);
        }
     },
     FIELD_B {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_B(rs.getString(position + 1);
        }
     };


     public String listFields() {
         StringBuilder sb = new StringBuilder();
         for (Column c: Column.values()) {
             if (sb.length() > 0) {
                 sb.append(",");
              }
              sb.append(c.name());
          }

           return sb.toString();
    }
}


で、もう一度、SQL文を組み立てるときは、

    String sql = "Select " + Column.listFields() + " From Some_table";

Dtoに値を放り込むときは、前回の記事で書いたIndexableIteratorがある前提で

    for (IndxableIterator.Pair<Column> pair: new IndexableIterator<Column>(Column.values())) {
        c.getValue().bind(c.getIndex(), resultSet, dto);
     }

ってやれば関連が強いものが近くに置かれて忘れ難くなった。フィールドが追加されたら、enumのところとdtoに追加すればいい。で、interfaceとenumはDTOの中にInner Classとして宣言すれば、関連性がより強くなって忘れにくい、変更箇所が局所化できますね。
それに、DAOの方はコードの変更が必要なくなるおまけ付き。

Java8のラムダとか、FunctionalInterafaceが入ってくると、各bindメソッドがラムダ式でもっと簡単に書けて、初期化の引数として渡せるので、かなりスッキリするはずです。


ということで、これくらいがJava7までの現実的な妥協点じゃないでしょうか?

最期におさらいをすると、enumはあなたが思っている以上にできる子なのです。