不厭其煩

Reder’s Blog, experimental version

Archive for the ‘Java’ Category

Builder Pattern

with 2 comments

什麼是 Builder Pattern?

Builder Pattern 是 Joshua Bloch 在 JavaOne 2007 的演講中提出的:利用在一個 class 中內置的 public static class Builder ,並將原先的 constructor 封裝在該 class 中,我們可以免除以下問題:

  • Ugly constructor. 例如:new NutritionFacts(int servingSize, int servings,
    int calories, int fat, int 15 more optional params!);
  • Constructor telescoping. 如果是上例的 constructor ,我們在使用的時候一定得參看原先的 constructor 說明,才能知道各個參數的意義。如:NutritionFacts locoCola =
    new NutritionFacts(240, 8, 0, 0, 30, 28);
    ,不看的話根本不知道那一串數字是什麼東西。
  • Too many setters required when creating objects. 如果不用像上例的方式,改用 Java Bean style setters 呢?因為沒有辦法強制必須要什麼參數設定了才能產生出一個新的 instance ,所以造成了不確定性和異變性。

Builder Pattern: 一個範例

例如我們有個 User 的 Java Bean ,其中 idusername 為必須。我們加上了一個 Builder 如下 。

public class User {
  private long id;
  private String username;
  private String firstname;
  private String lastname;
  private String email;

  public static class Builder {
    private long id;
    private String username;
    private String firstname;
    private String lastname;
    private String email;

    public Builder(long id, String username) {
      this.id = id;
      this.username = username;
      return this;
    }

    public Builder firstname(String firstname) {
      this.firstname = firstname;
      return this;
    }

    public Builder lastname(String lastname) {
      this.lastname = lastname;
      return this;
    }

    public Builder email(String email) {
      this.email = email;
      return this;
    }

    public User build() {
        return new User(this);
    }
  }

  private User(Builder builder) {
    this.id = builder.id;
    this.username = builder.username;
    this.firstname = builder.firstname;
    this.lastname = builder.lastname;
    this.email = builder.email;
  }
}

而我們就可以用下列的方式建立一個新的 User

public class UserCreator {
  public static void main(String[] args) {

    User user = new User.Builder(541, "jsmith").email("john@smith.com").build();

  }
}

但其實 Builder 的建立相當累人,是一堆重複性的 code 。不過我們有現成的 Eclipse Builder plugin 可以使用,幫助我們快速建立 Builder 。

More:

Written by Reder

08/31/2009 at 9:58 下午

張貼於Java

Tagged with

Mac OS X 10.5 設定 JDK 6 的方式

with 32 comments

原來 Mac OS X 10.5 原先就有安裝好 JDK 6 了。到 /Applications/Utilities/Java Preferences 去設定偏好順序,就可以使用 JDK 6 了。

Written by Reder

08/15/2009 at 8:10 下午

張貼於Java

Tagged with , ,

在 JSTL 中取用 Java constants

leave a comment »

以下程式碼來自討論串中。

在 Java 中,我們會使用 public static final String A_CONST  = "const"; 的方式設定常數,但在 JSTL 中無法直接取用。以下是解決方法:

  1. 由於 JSTL 可以取得 Map 或 JavaBean 的值,所以我們可以利用這個特性,建立一個 Class 繼承 HashMap 。然後用 relection 將其中的 fields 放入 Map 中。
    package com.utils;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Class to reveal java constants to JSTL Expression Language
     * Uses reflection to scan the declared fields of a Constants class
     * Adds these fields to the Map.
     * Map is unmodifiable after initialization.
     *
     */
    public class JSTLConstants extends HashMap {
    	private boolean initialised = false;
    
    	public JSTLConstants() {
    		Class c = this.getClass();
    		Field[] fields = c.getDeclaredFields();
    		for (int i = 0; i < fields.length; i++) {
    
    			Field field = fields&#91;i&#93;;
    			int modifier = field.getModifiers();
    			if (Modifier.isFinal(modifier) && !Modifier.isPrivate(modifier))
    				try {
    					this.put(field.getName(), field.get(this));
    				}
    				catch (IllegalAccessException e) {}
    		}
    		initialised = true;
    	}
    
    	public void clear() {
    		if (!initialised)
    			super.clear();
    		else
    			throw new UnsupportedOperationException("Cannot modify this map");
    	}
    
    	public Object put(Object key, Object value) {
    		if (!initialised)
    			return super.put(key, value);
    		else
    			throw new UnsupportedOperationException("Cannot modify this map");
    	}
    
    	public void putAll(Map m) {
    		if (!initialised)
    			super.putAll(m);
    		else
    			throw new UnsupportedOperationException("Cannot modify this map");
    	}
    
    	public Object remove(Object key) {
    		if (!initialised)
    			return super.remove(key);
    		else
    			throw new UnsupportedOperationException("Cannot modify this map");
    	}
    }
    &#91;/sourcecode&#93;</li>
    	<li>然後我們的 Constants Class 再繼承上面的 Class: 
    package com.utils;
    
    import java.util.*;
    public class JSTLConstantsTest extends JSTLConstants {
    
    	public static final String name = "Evnafets";
    	public static final int age = 28;
    	private static final String bad = "bad";
    	public static final String programmingSkill = "Awesome";
    	public static final String[] daysOfTheWeek = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    	public int temp = 100;
    
    	public static void main(String[] args) {
    		Map m = new JSTLConstantsTest();
    
    		System.out.println("Tee constants are ");
    		for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
    			Map.Entry me = (Map.Entry) it.next();
    			System.out.println(me.getKey() + " = " + me.getValue());
    		}
    	}
    }
    
  2. 那麼在 JSP 頁面上我們就可以這樣取用:
    <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
    <jsp:useBean id="Constants" class="com.utils.JSTLConstantsTest"/>
    <c:out value="${Constants.name}"/>
    <c:out value="${Constants.age}"/>
    <c:forEach var="day" items="${Constants.daysOfTheWeek}">
      <c:out value="${day}"/>
    </c:forEach>
    

在討論串中另有針對無法繼承的 Interface 或 third party class 的改進法,但基本上我想我個人應該用不到,所以就不整理了。

Written by Reder

07/31/2008 at 3:09 下午

張貼於Java

Tagged with , ,