Page List

Search on the blog

2012年8月31日金曜日

デザインパターン(7) Builder

まえおき
以下の書籍でBuilderパターンについて勉強した。


まとめ
  • 構造を持ったインスタンスを組み上げるときに利用する。
  • Builder、ConcreteBuilder、Director、Clientによって構成される。
疑問点
  • Builderパターンはオブジェクト生成のためのデザインパターン。Factory Methodパターンと何が違うのか?
Factory Methodパターンは異なる種類のオブジェクトを生成するときのパターンで、Builderパターンはオブジェクトの生成手順をきれいにまとめるためのパターンなので、目的がまったく違う。以下のような記述が参考サイト[1]にあった。
The rule of thumb I noticed after some time was the following: Consider a restaurant. The creation of "Todays Meal" is a factory pattern, because you tell the kitchen "get me todays meal" and the kitchen/factory decides what object to generate. based on hidden critereas.

The builder appears if you ordered a custom pizza. In this case, the waiter tells the chef/builder "I need a pizza, add cheese, cheese, onions and bacon to it!". Thus, the builder exposes what attributes the generated object should have, but hides how to set them.
  • パッと見、Template Methodパターンと同じに見えるんだけど、何が違うのか?
これは明確な違いが自分ではよく分からなかった。Builderパターンの方が抽象度や独立性が高いような気がする。Template Methodパターンだと親-子クラスという関係があるし、同じ部品を別の処理フローでテンプレート化したいときに処理フローの数だけ親-子のペアを毎回書かないといけないような気がする。それに比べて、Builderパターンの方はdirector-builder間の関係が移譲なのでそれぞれの独立性が高いのかなと思う。参考サイト[2]になんとなくしっくりくるような説明があった。

Template method is really just a way to define some methods that each subclass must define.

The builder pattern is used to construct a more complex object.

Lets say that we want to construct different Saab (car brand) models. Each model has different engines,lights etc.

If we were to use the template method pattern we had to create one class for each single combination of cars or use some nasty inheritance hierarchies. A lot of those methods would also contain duplicate code.

With the build pattern we can instead take different parts and compose those together to a complete car. Hence we can reuse a engine for every model if needed and we can also customize each part of the car.

その他
  • 書籍の練習問題がおもしろかった。久しぶりにswingでGUIを書いた。今度簡単なゲームか何か書いてみようかな。
参考サイト
  1. When would you use the Builder Pattern? [closed]
  2. Differences between builder pattern vs template method

2012年8月29日水曜日

Spring Framework -Aspect Oriented Programming-

Spring特集第3弾。Aspect Oriented Programming(以下AOP)について書きます。

AOPとは?
共通的な機能を後から付け加える仕組みです。 具体的に言うと、
  1. ロギング
  2. キャッシング
  3. セキュリティ
  4. 認証
などの共通的に利用される機能をビジネスロジックから切り離して、後から横断的に追加できるような仕組みのことです。

Before AdviceとAfter Advice
まずは、一番簡単なBefore AdviceとAfter Adviceの例を書きます。Adviceとは、AOPの用語で追加する共通処理のことです。何をやっているかは以下のサンプルを見れば一目瞭然です。
// src/cc/co/goodpreparations/Person.java
package cc.co.goodpreparations;

public class Person {
    public void smile() {
        System.out.println("s/he is smiling.");
    }
    
    public void cry() {
        System.out.println("s/he is crying.");        
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- // src/Beans.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

    <aop:config>
        <aop:aspect id="myaop" ref="aoptest">
            <aop:pointcut id="all"
                expression="execution(* cc.co.goodpreparations.*.*(..))" />            
            <aop:pointcut id="smile"
                expression="execution(* cc.co.goodpreparations.*.smile(..))" />
            <aop:before pointcut-ref="all" method="beforeAdvice" />
            <aop:after pointcut-ref="smile" method="afterAdvice" />
        </aop:aspect>
    </aop:config>

    <bean id="person" class="cc.co.goodpreparations.Person">
    </bean>

    <bean id="aoptest" class="cc.co.goodpreparations.AOPTest" />
</beans>
// src/cc/co/goodpreparations/AOPTest.java
package cc.co.goodpreparations;

import org.aspectj.lang.ProceedingJoinPoint;

public class AOPTest {

    public void beforeAdvice() {
        System.out.println("@This is a before advice.");
    }

    public void afterAdvice() {
        System.out.println("@This is an after advice.");
    }
}
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");

      Person person = (Person) context.getBean("person");
      
      person.smile();
      System.out.println("---------------------------------");
      person.cry();
   }
}
ポイントとなる設定ファイルの書き方を説明します。AOPの設定は、aop:config要素の中に書きます。aop:aspectの中に、Aspectの設定を書きます。Aspect=Advice + (処理を埋め込む場所)です。ちなみに(処理を埋め込む場所)のことをPointcutと呼びます。
Aspect = Advice + Pointcut
と覚えておくとよいです。設定ファイルの説明に戻ります。簡単に設定箇所を纏めると以下のようになります。
  1. aop:aspect要素のid属性にAspectのIDを、ref属性にAdviceが定義されたクラスのBean IDを書きます。
  2. aop:pointcut要素のid属性にPointcutのIDを、expression属性に共通処理を埋め込みたい場所を正規表現で書きます。
  3. aop:before要素のpointcut-ref属性に使用するPointcutのIDを、method属性に1.で指定したBeanのメソッド名を書きます。(このメソッドがAdviceになる)
  4. aop:after要素もaop:before要素と同様に書きます。
実行結果は、以下のようになります。
@This is a before advice.
s/he is smiling.
@This is an after advice.
---------------------------------
@This is a before advice.
s/he is crying.
このようにAOPを利用すると、任意の処理を任意の場所に後から埋め込むことができます。

その他のAdvice
Before Advice、After Adviceの他にもAdviceはあります。以下にAdviceの種類を纏めます。
種類 用途
Before Advice 処理をメソッドの実行前に追加したい場合。
After Advice 処理をメソッドの実行後に追加したい場合。
Around Advice 処理をメソッドの実行前後に追加したい場合。
After-returning Advice 処理をメソッドが正常終了した後に追加したい場合。
After-throwing Advice 処理をメソッドが異常終了した(例外がスローされた)後に追加したい場合。
このように、どのタイミングでAdviceを挿入したいかに応じて様々な種類のAdviceを使うことができます。それぞれのAdviceの使用方法はSpringSource.orgのreferenceを参照してください。

まとめ
DIがオブジェクト間の依存性を外部に掃き出し、それを後から注入する機能だと考えると、AOPはオブジェクトと共通機能の依存性を外部に掃き出し、それを後から注入する機能だと考えることができます。AOPを使うことで機能追加/変更に強いソースコードを書くことができます。

2012年8月28日火曜日

Spring Framework -Dependency Injection-

Spring FrameworkのDependency Injection(以下DI)の機能について書きます。

"bought a bracelet"

DIとは?
いい例が浮かばなかったのですが、例えば以下のようなプログラムを考えてみてください。
// src/cc/co/goodpreparations/Investor.java
package cc.co.goodpreparations;

public class Investor {
    public void buy() {
        GoodCalculator calculator = new GoodCalculator();
        
        // do something

    }
}
// src/cc/co/goodpreparations/GoodCalculator.java
package cc.co.goodpreparations;

public class GoodCalculator {

    public double calculate() {
        // do difficult calculations
        
        return 0;
    }
}
何かに投資するInvestorクラスがあって、投資するために複雑な計算をします。その計算にGoodCalculatorというクラスを使おうというシチュエーションです。
上のように書いてしまうと、InvestorクラスはGoodCalculatorクラスが無いと使用できません。つまり、InvestorクラスはGoodCalculatorクラスに依存しています。一般にクラスが別のクラスに依存していると、

  • クラスの独立性が低いため、再利用しにくい
  • 独立したテストが行い辛い
というデメリットがあります。

Investorの例に戻ります。もし、今使われているGoodCalculatorより優秀なBetterCalculatorが開発されて、BetterCalculatorを使おう。となったらどうでしょう?GoodCalculatorを使っている場所をすべて書き直さなければなりません。使われている場所が1ヶ所だけならいいですが、何10箇所、何100箇所もあったら大変です。

以下のようにするとどうでしょうか?
// src/cc/co/goodpreparations/Calculator.java
package cc.co.goodpreparations;

public interface Calculator {
    public double calculate();
}
// src/cc/co/goodpreparations/GoodCalculator.java
package cc.co.goodpreparations;

public class GoodCalculator implements Calculator {

    @Override
    public double calculate() {
        // do difficult calculations
        
        return 0;
    }
}
// src/cc/co/goodpreparations/Investor.java
package cc.co.goodpreparations;

public class Investor {
    Calculator calculator = null;
    
    public Investor(Calculator calculator) {
        this.calculator = calculator;
    }
    
    public void buy() {
        // do something with the given calculator

    }
}
こうすると、Investorは中身がどのように実装されているかは知りませんが、Calculatorインターフェースを実装した何らかのクラスを使うことになります。GoodCalculatorがBetterCalculatorに変更されても、そもそもGoodCalculatorというクラス名を直接ソースコード上に書いていないので変更は生じません。もしBetterCalculatorがcalculateメソッドを実装していなければ、Adapterデザインパターンを使ってCalculatorインターフェースを実装するクラスを作ればいいでしょう。
さて、実際にどのCalculatorを使用するかですが、設定ファイルに記述してSpring Frameworkに具体的なクラスを注入してもらいましょう。このように、ソースコードからクラス間の依存性を取り除き、外部から依存性を注入することをDIと呼びます。以下では、
  1. コンストラクタによるDI
  2. setterによるDI
の2種類のDIを説明します。

コンストラクタによるDI
全章の後半で導入したように、コンストラクタで使用するCalculatorを渡す場合は以下のようにすればDIができます。ポイントはXML設定ファイルのinvestorのbean定義のconstructor-arg要素の部分です。この部分でコンストラクタに渡す具体的なクラスを指定しています。注入する具体的なクラスを変えたい場合は、この部分を変更するだけでOKです。
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Investor investor = (Investor)context.getBean("investor");
        investor.buy();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <bean id="goodCalculator" class="cc.co.goodpreparations.GoodCalculator"></bean>
   <bean id="investor" class="cc.co.goodpreparations.Investor">
            <constructor-arg ref="goodCalculator"/>
   </bean>
</beans>
setterによるDI
同様にsetterを利用して、具体的なクラスを注入することができます。
// src/cc/co/goodpreparations/Investor.java
package cc.co.goodpreparations;

public class Investor {
    Calculator calculator = null;
    
    public void setCalculator(Calculator calculator) {
        this.calculator = calculator;
    }
    
    public void buy() {
        // do something with the given calculator
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <bean id="goodCalculator" class="cc.co.goodpreparations.GoodCalculator"></bean>
   <bean id="investor" class="cc.co.goodpreparations.Investor">
           <property name="calculator" ref="goodCalculator"/>
   </bean>
</beans>
setterを利用したDIでは、まず引数なしコンストラクタでInvestorクラスをインスタンス化した後、setterでcalculatorを設定しています。使用するcalculatorを変えたい場合は、investorのbean定義のproperty要素のref属性を変更すればOKです。

どちらを使うべきか?
コンストラクタを使用したDIとsetterを使用したDIを説明しました。「で、どっち使えばいいの?」という疑問が浮かぶと思いますが、必須の依存性を注入したい場合はコンストラクタによるDI、オプショナルな依存性を注入する場合はsetterを使用したDI、という使い分けをするのが一般的です。必要に応じて両方同時に使うことも可能です。

Spring Framework -オブジェクトの生成-

Spring Frameworkについて、基本的な機能を簡単に紹介します。
  1. オブジェクトの生成
  2. Dependency Injection
  3. Aspect Oriented Programming
の3つの機能を3回のpostに分けて書きます。まずは、オブジェクトの生成から書きます。

XML設定ファイルを利用したオブジェクトの生成
// src/cc/co/goodpreparations/Main.java 

package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person =  (Person)context.getBean("person");

        person.saySomething();
    }
}
// src/cc/co/goodpreparations/Person.java

package cc.co.goodpreparations;

public class Person {
    private String message;

       public void setMessage(String message){
          this.message  = message;
       }

       public void saySomething(){
          System.out.println(message);
       }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
XMLファイルにBeanのidとクラスのマッピングを記述します。使用者はidを指定して対応するクラスのオブジェクトを生成します。普通にnewすればいいんじゃない?と思う人もいるかもしれませんが、上記のようにSpringが提供するコンテナからオブジェクトを生成することで、DI/AOPといった機能が使えるようになります。

フィールド値の設定
オブジェクトを生成するときにフィールドの初期値を設定出来ます。同一のクラスから生成されているがフィールド初期値が異なるインスタンスは、異なるBean idをつけることで区別できます。XMLのproperty要素内でフィールドの設定をしていますが、ここで設定するフィールドには必ずsetter(この例の場合はPerson#setMessage)を定義しなければいけません。(JavaBeansなので当然ですが。)
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person taro =  (Person)context.getBean("taro");
        taro.saySomething();
        
        Person hanako =  (Person)context.getBean("hanako");
        hanako.saySomething();
        
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="taro" class="cc.co.goodpreparations.Person">
       <property name="message" value="ぼく太郎!"/>
   </bean>
   <bean id="hanako" class="cc.co.goodpreparations.Person">
       <property name="message" value="わたし花子!"/>
   </bean>
</beans>
と、このように太郎くんと花子さんを作れます。

Beanのスコープ
Beanを生成するときに、そのスコープを設定することができます。
  1. singleton
  2. prototype
  3. request
  4. session
  5. global-session
3.-5.はWebアプリケーションに特化したものなので、ここでは1.と2.のみを説明します。まずはsingleton
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person = (Person)context.getBean("person");
        person.setMessage("Goodbye!");
        person.saySomething();
        
        Person person2 = (Person)context.getBean("person");
        person2.saySomething();
        
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person" scope="singleton">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
scope="singleton"のところに注目です。名前から想像がつくように、scopeをsingletonにすると同一のidを持つBeanはアプリケーション上で一つしか作られません。つまり、context#getBeanは毎回同じインスタンスの参照を返します。実行結果は
>Goodbye!
>Goodbye!
となります。ちなみにデフォルトのスコープはsingletonです。scope属性を明記しなかった場合、そのBeanのスコープはsingletonになります。
次に、prototypeを試してみます。先ほどと同様の例でscope属性のみをprototypeに変更すると、実行結果は
>Goodbye!
>Hello!
になります。スコープをprototypeにすると、毎回異なるインスタンスが生成されます。

コールバック関数の指定
Beanが生成されたとき/破棄されるときに、何か処理をしたい場合はコールバック関数を指定することができます。
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person = (Person)context.getBean("person");
        person.saySomething();
        person = null;
         ((AbstractApplicationContext) context).registerShutdownHook();
    }
}
// src/cc/co/goodpreparations/Person.java
package cc.co.goodpreparations;

public class Person {
    private String message;

       public void setMessage(String message){
          this.message  = message;
       }

       public void saySomething(){
          System.out.println(message);
       }
       
       public void initFunc() {
           System.out.println("A Person Bean is created!");
       }

       public void destroyFunc() {
           System.out.println("A Person Bean is destroyed!");
       }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person" scope="singleton"
            init-method="initFunc" destroy-method="destroyFunc">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
XMLファイルのbean要素のinit-method属性、destroy-method属性にて、コールバックしたい関数を指定することができます。これは便利です。mainメソッド内でAbstractApplicationContext#registerShutdownHookを呼んでいますが、これを呼ぶことで確実にBeanが破棄されdestroy-methodで指定した関数が呼ばれるようにしています。


2012年8月26日日曜日

デザインパターン(6) Prototype

まえおき
Prototypeパターンの勉強をしました。書籍だけで大まかなイメージは掴めましたが、「複雑な過程を経てインスタンス生成されるものを簡単に作れる」という例があると、より分かりやすいと思います。


まとめ
  • プロトタイプと呼ばれるオブジェクトをコピーすることで、複雑な過程を経てインスタンス化されるオブジェクトの生成を簡単にすることができる。
  • コピーされたオブジェクトは、プロトタイプとは独立しているので、必要に応じてフィールドの内容を変更することができる。(参考サイト[2,3])
疑問点
  • 書籍には「複雑な過程を経てインスタンス生成されるものを簡単に作れる」という例が無くて具体的なイメージが湧かなかった。参考サイト[1]を見て複雑な過程(もしくは時間のかかる処理)を経て作られるインスタンスのイメージが掴めた。

その他
  • cloneメソッドとCloneableインターフェースに関して学んだ。cloneメソッドはshallow copyなので対象オブジェクトに参照型のフィールドが存在する場合は本当にshallow copyでよいのか注意する。
参考サイト
  1. TECHSCORE
  2. THE CODE PROJECT
  3. javapapers

2012年8月22日水曜日

Ubuntu12.04のキーボード設定


"Sunset on Beach Stage"

キーボードの設定を変えました。

HUDの無効化
デフォルトでは、Altキーを押すとHUDが立ち上がります。Altキーを押す度にウィンドウが開いてフォーカスが移り面倒なので、このサイトを参考にHUDを無効化しました。

右Altキーの設定
やっぱり右Altキーは欲しいです。ということで、以下の手順で変換キーを右Altキーに割り当てました。
  1. コマンドラインにxevと入力する。
  2. 変換キーを押すと、変換キーのkeycode(100)が表示される。
  3. ~/.Xmodmapに以下を設定
keycode 100 = Alt_L
add mod1 = Alt_L

2012年8月17日金曜日

GETとPOSTの違い

GETとPOSTの違いについて勉強しました。

HTML specificationsによる定義/推奨
■ GET
  • データはURLに含まれる。
  •  idempotentな(永続的な効果をもたらさない、副作用をもたらさない)処理を行うときに使うことが推奨されている。 ⇒データを取得するときに使用する。

■ POST
  • データはmessage body部分に含まれる。 
  • idempotentではない処理を行うときに使うことが推奨されている。 ⇒データのソート、更新、商品の注文、Emailの送信など。

実用的な違い/留意点
  • GETはサーチエンジンのクローラーに踏まれる可能性があるので、副作用のある処理をGETで処理すると、不用意にデータを消去されたり、更新されたりする可能性がある。
  • GETリクエストに対するレスポンスはキャッシュできる(※)場合が多い。POSTリクエストに対するレスポンスがキャッシュされることはほとんどない。
  • GETはURLをブックマーク保存できる。
  • GETはURLにデータが載るので、Webサーバやプロキシサーバーのログに残る。リンクで他ページに遷移したときにRefererのところにも載る。⇒パスワードなどのセンシティブな情報を送る場合はGETは避けるべき。
  • GETにはASCII文字以外を含めない方がいい。(原則上は扱えないが、実用上は扱える。)マルチバイト文字をクエリーに含む検索処理の場合は、POSTを使う方が(idempotent=GETの基本精神に反するが)ベター。
  • GETはPOSTより送信できる情報量が少ない。
  • ブラウザの「戻る」ボタン⇒POSTは警告を上げる。GETはそのまま遷移。
(※)ちなみにキャッシュはいろいろな種類があって、
  • ブラウザーキャッシュ
  • プロキシーキャッシュ
  • ゲートウェイキャッシュ(リバースプロキシー)
などがあります。


まとめ
基本的には、データのREAD処理の場合はGETを使い、CREATE/UPDATE/DELETE処理の場合POSTを使えばよいと思います。あとはセキュリティの観点からセンシティブな情報を送信する場合はPOSTを使うべきです。

参考サイト
  1. Methods GET and POST in HTML forms - what's the difference?
  2. Get vs Post
  3. CACHING TUTORIAL