デザインパターン勉強会#dezapatan FlyWeightパターン

もう何回目か忘れてしまいましたが、自分の担当だったので。

サンプルは今回はjsで書いてみました。入力された数字をCanvasで画像を読み込んで表示する簡単なものです。画像を読み込む部分をFlyweightパターンを使って見ました。
http://kuidaoring.appspot.com/dezapatan/flyweight/flyweight.html:サンプル

java.lang.Integer#valueOfのソースを見てみたよ

Dezapatanの自分の担当がFlyweightパターンということで例を探していたところ、StackOverFlowにjavaのapiの中で使われているデザインパターンまとめみたいなのがあった。
Flyweightの部分を参照するとInteger#valueOfでFlyweightパターンが使われてるとのことで早速ソースを見てみた。

    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

コード見ると-128からIntegerCache.highまでの範囲はIntegerCache.cache配列にあるオブジェクトを返しているみたい。
IntegerCacheってなんなのって言うとIntegerの内部クラスで以下のような実装になってる。

  private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }

cacheHighは基本的には127なので、つまり-128から127までのIntegerオブジェクトはあらかじめ作ってある様子。
以下のようなテストでちょっと確認してみる。

class FlyWeightPaTan {

    public static void main(String[] args) {
        Integer a = new Integer(127);
        Integer b = Integer.valueOf(127);
        Integer c = Integer.valueOf(127);

        System.out.println(a == b ? "a == b" : "a != b");
        System.out.println(a == c ? "a == c" : "a != c");
        System.out.println(b == c ? "b == c" : "b != c");

        System.out.println("----------");

        Integer aa = new Integer(128);
        Integer bb = Integer.valueOf(128);
        Integer cc = Integer.valueOf(128);

        System.out.println(aa == bb ? "aa == bb" : "aa != bb");
        System.out.println(aa == cc ? "aa == cc" : "aa != cc");
        System.out.println(bb == cc ? "bb == cc" : "bb != cc");

    }
}

実行結果は以下のような感じで、b == cとなるので127まではちゃんとキャッシュされたものが使われているみたい。

$ java FlyWeightPaTan
a != b
a != c
b == c
----------
aa != bb
aa != cc
bb != cc

ここまで書いといて、Flyweightって必要になったときにnewしてその結果をキャッシュするようなパターンだからあらかじめ需要が高そうな?ものを作っておくっていうのはもしかしてFlyWeightじゃないんじゃ…?みたいな気がしたけど、どうなんだろう…

YUIのScollViewを入れ子にしてみる

ScrollViewの中にもう一つScrollViewを作りたくなったのでメモ。

テストページ。
http://kuidaoring.appspot.com/sandbox/innerscroll.html

  YUI().use("scrollview", function(Y){
            new Y.ScrollView({
                height : 500,
                srcNode: '#outerlist'
            }).render();

            new Y.ScrollView({
                height : 200,
                srcNode: '#innerlist'

            }).render();

            Y.one('#listWp').on('gesturemovestart', function(e){
                e.halt();
            });
        });

ScrollViewがgesturemovestartでスクロールを検知しているようなので、内側のスクロールビューを囲うdivを用意して、そのdivでgesturemovestartイベントを拾って上に行かない様にするだけ。

java.util.CalendarのgetInstanceのソースを見てみたよ

今日のdezapatanででた話題について調べてみた。
今日はprototypeパターンについての会だったんですが、CalendarクラスのgetInstanceもprototypeっぽい挙動だよねーみたいな話になり、でもgetInstanceって言ってるしSingletonなんじゃねみたいな感じになり、
webで調べてみると実はSingletonでもprototypeでもなくてFactoryパターンだよという事が分かりました。
で、実際どういうソースになってるのかみてみたメモ。

まずgetInstanceについて見てみる。

    public static Calendar getInstance()
    {
        Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault());
	cal.sharedZone = true;
	return cal;
    }

createCalendarにパラメータ設定してCalendarオブジェクト作ってるぽい。
次にcreateCalendarを見てみる。

    private static Calendar createCalendar(TimeZone zone,
					   Locale aLocale)
    {
	// If the specified locale is a Thai locale, returns a BuddhistCalendar
	// instance.
	if ("th".equals(aLocale.getLanguage())
	    && ("TH".equals(aLocale.getCountry()))) {
	    return new sun.util.BuddhistCalendar(zone, aLocale);
	} else if ("JP".equals(aLocale.getVariant())
		   && "JP".equals(aLocale.getCountry())
		   && "ja".equals(aLocale.getLanguage())) {
	    return new JapaneseImperialCalendar(zone, aLocale);
	}	    

	// else create the default calendar
        return new GregorianCalendar(zone, aLocale);	
    }

タイムゾーンやlocaleによって作るオブジェクトを変えているみたい。やっぱFactoryだ。

ということでやはりCalendar.getInstanceはFactoryでしたよと。
でもgetInstanceという名前だとSingletonっぽく思ってしまう罠ですね。
ていうかBuddhistCalendarとJapaneseImperialCalendarって初めて知った。

デザインパターン勉強会 #8 Compositeパターン

今回はCompositeパターン。前回の復習がサボり気味だったので、今回はサンプルコードも書いてみました。

Compositeパターンは、容器となるオブジェクトと終端(木構造で言えば葉になる要素)のオブジェクトとを同一に扱うためのパターンです。クライアントからすると同じ操作で2つを区別せずに使う事が出来ます。
よくサンプルとして出てくるのが、木構造のもの、ディレクトリとファイルなどです。

早速例を。今回は箇条書きを書くプログラムをCompositeパターンで書いてみました。

クラス図とソースはこんな感じ。

ListComponent

abstract class ListComponent {
    public void print(){
        print("");
    }
    abstract void print(String prefix);
    abstract void add(ListComponent items);
}

AbstractListComponent

import java.util.List;
import java.util.ArrayList;

abstract class AbstractListComponent extends ListComponent {
    private List<ListComponent> items;
    private String title;

    public AbstractListComponent(String title){
        items = new ArrayList<ListComponent>();
        this.title = title;
    }

    public void print(String prefix){
        System.out.println(title);
        for(ListComponent item : items){
            System.out.print(prefix);
            printPrefix();
            item.print(prefix + "  ");
        }
    }

    public void add(ListComponent item){
        items.add(item);
    }

    abstract void printPrefix();
}

OrderedList

class OrderedList extends AbstractListComponent {
    private int number;

    public OrderedList(String title){
        super(title);
        number = 1;
    }

    public void printPrefix(){
        System.out.print(Integer.toString(number++) + " ");
    }
}

UnorderedList

class UnorderedList extends AbstractListComponent {

    public UnorderedList(String title){
        super(title);
    }

    public void printPrefix(){
        System.out.print("- ");
    }

}

Text

class Text extends ListComponent {
    private String text;

    public Text(String text){
        this.text = text;
    }

    public void print(String prefix){
        System.out.println(text);
    }

    public void add(ListComponent item){
        return;
    }
}

Main

class Main {
    public static void main(String[] args){
        OrderedList ol = new OrderedList("Root Ordered List");
        ol.add(new Text("text1"));

        UnorderedList ul = new UnorderedList("Child Unordered List");
        ul.add(new Text("hogehoge"));
        ul.add(new Text("fugafuga"));

        OrderedList ol2 = new OrderedList("OrderedList 2");
        ol2.add(new Text("ListItem A"));
        ol2.add(new Text("ListItem B"));

        ul.add(ol2);

        ol.add(ul);
        ol.add(new Text("ol2"));

        ol.print();
    }
}

実行結果

$ java Main
Root Ordered List
1 text1
2 Child Unordered List
  - hogehoge
  - fugafuga
  - OrderedList 2
    1 ListItem A
    2 ListItem B
3 ol2

ルートにある要素のprintメソッドを叩けば全体をダンプしてくれるような感じ。葉にあたるTextクラスと順序ありのリストのOrderedList,順序なしのUnorderedListクラスを区別なくaddできるようになっています。今回の例ではAbstractListComponentのprintメソッドの部分はTemplateMethodパターンっぽくもなっていると思います。

デザインパターン勉強会#7 Facadeパターン

デザインパターン勉強会第7回はFacadeパターンです。第6回はAdapterパターンでしたが欠席しました。。あとで復習しないと。

Facadeパターンでは、複数のクラスを使って何か処理を行うときに、その処理を窓口となる一つのクラスに集約する。

勉強会中にでた話題としては以下のような感じ。

  • Facadeへの移行は位なんと側にあったコードを集約するクラス(Facade)にコピペする感じでいい
  • Facadeに処理を集約することで、変更が生じたときにFacadeクラスを修正すればよく、クライアントコードに影響が少ない。
  • よくできたFacadeパターンはFacadeパターンであることをクライアントに意識させないはず。(Facadeの向こう側にあるパーツになるクラス群はクライントには見えないはず)
  • Facadeが用意していないような機能をクライントがほしがったときには困る。
  • TemplateMethodパターンとかStrategyパターンに似てる気がするよねー
  • Facadeになる部分をインタフェースとしてAPIを定義できると、違ったFacadeがいくつも用意できるんじゃない?

Facadeパターンのwikipediaに書いてあることですが、Facadeが集約するクラス群のアクセス修飾子を付けない事によって、同じパッケージからしかそのクラスをしようできなくなり、情報の隠蔽ができる。(protectedだと同じパッケージもしくはそのサブクラスなので、パッケージのそのからでも見えるっちゃ見えるのか?)

とまあ、こんな感じ。なんか雑なまとめな気がするけど、とりあえずということで。。。