การลงทุนจำเป็นไหม

พฤศจิกายน 24, 2009 iknight ใส่ความเห็น

ผมมักจะเห็นแม่กับแฟนผมคุยกันประจำเรื่องจะเอาเงินที่ครบดิลไปฝากที่ไหน เห็นอย่างนี้มาหลายปี แฟนผมก็เป็นที่ปรึกษาชั้นยอด หาข้อมูลอัตราดอกเบี้ยและระยะเวลาในการฝากมาให้แม่ผมเลือกเป็นประจำ พร้อมให้คำแนะนำ

ผมเลยถือโอกาศอธิบายเรื่องเงินเฟ้อให้แม่ผมฟัง ( ซึ่งแม่ผมก็เข้าใจดีอยู่แล้วถึงเรื่องค่าของเงินที่ลดลงเมื่อเวลาเปลี่ยนไป ) ผลตอบแทนที่เราได้จาก ธนาคาร สลากออมสิน หรือแม้กระทั่ง กอนทุนต่าง โดยส่วนมาก จะได้ประมาณ 0.75 – 3.75 ต่อปี ( ขึ้นอยู่กับระยะเวลาด้วยนะ )

โดยเฉลี่ยก็ประมาณ 2% ต่อปี ในขณะที่รัฐบาลประกาศอัตราเงินเฟ้อทุกปี ประมาณ 5% นั่นก็หมายความว่า พอครบ 1 ปี จาก 100 บาท ค่าเงินของเราควรจะเป็น 105 แต่เรากลับมีเงิน 102 บาท ( ค่าของเงินก็เป็น 102 บาท ) แน่นอนการเอาเงินไปฝาก ธนาคารไม่สามารถรักษาค่าเงินเอาไว้ได้ และดูจะไม่มีทางรักษาค่าเงินไว้ได้

สรุปว่า
ทุกปีที่ฝากเงินธนาคารค่าของเงิน จะลดไป 2.86% (102-105)/105 * 100 = 2.86%

มันจะกระทบกับเรายังไง ในเมื่อเงิน 100 บาท มันก็เป็น 102 บาท จริงๆนะ… แล้ว 105 บาทอะเอามาจากไหน … อืมก็จริง

มันจะไม่กระทบกับเราในวันที่เราได้เงิน 102 บาทคืนมาหรอกครับ แต่มันจะกระทบกับเราก็ต่อเมื่อเราใช้มัน เพราะฉะนั้นมันกระทบกับเราแน่นอน เพราะจะมีประโยชน์อะไรหากมีเงินแต่ไม่เอามาใช้ ( อืม… มีเงินต้องเอามาแลกของแน่นอน )

ลองคิดดูหากจะซื้อของซักอย่างราคา 100 บาท ( แต่ก็ไม่ได้จำเป็นอะไรมากมาย ) เลยยังไม่ซื้อ เอาเงินไปเก็บไว้ก่อน 1 ปีผ่านไป เงินที่มีอยู่จะเป็น 102 บาท ในขณะที่ราคาของจะเป็น 105 บาท (1 ปีผ่านไปซื้อไม่ได้แล้วนะ )

เอาไงดี งั้นถ้าไม่รู้จะเอาเงินไปทำอะไรให้ได้ผลตอบแทนมากกว่า 5% อยากได้อะไรซื้อเลยดีไหม หากอยากได้อะไรซื้อเลย เวลาผ่านไป 5 ปี ก็จะมีของอย่างหนึ่งอายุ 5 ปี 1 อัน มูลค่าของมัน อาจจะหมดแล้วก็ได้มั้ง

แต่หากสามารถ หาผลตอบแทนของเงินได้อย่างน้อยเท่ากับ
อัตราเงินเฟ้อ 5% ต่อปี ก็จะรักษามูลค่าของเงินเอาไว้ได้
หากทำได้มากกว่า นั้นก็คือค่าเหนื่อยที่เราควรจะได้รับ

และถ้าทำได้ 5 ปี 10 ปี ติดต่อกัน คุณจะได้เห็น พลังของผลตอบแทนทบต้น

นี่คงจะเป็นเหตุผลแรกของคำถามว่า การลงทุนจำเป็นไหม

ปล. เรื่องเงินเฟ้อเป็นเรื่องที่สำคัญมาก และมีรายละเอียดอีกพอสมควร
หาอ่านได้ในหนังสือ ศาสตร์แห่งบัฟเฟตต์ (Buffettology)
แต่เป็นเงินเฟ้อในมุมมองของนังลงทุนนะ ไม่ใช่มุมมองของเศรษฐศาสตร์
ปล. หนังสือเล่มนี้แปลดีมาก

Categories: Investment

Use enums instead of int constants

สิงหาคม 1, 2009 iknight ใส่ความเห็น

ก่อนที่จะมีการใช้ enum ใน Java5 Java Version ก่อนหน้านี้ก็มีการใช้
constants ที่เรียกว่า int enum pattern หน้าตาจะเป็นแบบนี้นะครับ

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

มาดูข้อเสียของมันดีกว่า
1. มันไม่ type safety
เราสามารถจะ assign ค่าอะไรให้มันก็ได้

2. มันไม่มี namespaces
โดยเราต้องใช้ parameter name ที่มี prefixe เหมือนกันในการจักกลุ่ม

3. มันเป็น compile-time constant
ถ้า build client หรือ class ที่เรียกใช้มัน มันจะ build โดยไปเอาค่า
constant มาเก็บไว้ที่ class มันเลย ลองดูตัวอย่างนี้หน่อยดีกว่า

int enum pattern “Apple.java”

public interface Apple{
	public static final int APPLE_FUJI = 0;
	public static final int APPLE_PIPPIN = 1;
	public static final int APPLE_GRANNY_SMITH = 2;
}

class ที่ต้องการใช้ constant ก็ impliments มา “TestApple.java”

public class TestApple implements Apple{
	public static void main(String[] args) {
		System.out.print(APPLE_FUJI);
		System.out.print(APPLE_PIPPIN);
		System.out.print(APPLE_GRANNY_SMITH);
	}
}

ค่าที่ได้จะเป็น 012 นะครับ แต่ถ้าลองแก้ไขค่าของ constant ของ Interface Apple แล้ว build ใหม่(build แต่ Interface Apple นะครับ)แล้วลอง run class TestApple ค่าที่ได้ก็จะได้ค่าเหมือนเดิม แต่ถ้าอยากได้ค่า constant ใหม่ก็ต้อง build class TestApple ใหม่ด้วยเพื่อให้มันไปอ่านค่า constant มาใหม่

4. มัน print value ของ constant ได้เท่านั้น
เวลา print ออกมาจะได้แต่ค่าที่ constant เก็บไว้เท่านั้นนะครับ

หรืออาจจะเจอ pattern คล้ายๆกัน โดย constant เก็บค่า String เรียกว่า string enum constant แต่มันจะนำไปสู่ปัญหาของ performance ยิ่งกว่านั้นมันทำให้ programmer สามารถ hard-code value ของ string constant แทนการใช้ field name และมันจะมีโอกาศพิมพ์ผิด มันจะเกิดข้อผิดพลาดตอน runtime ทั้งๆที่ มันสามารถค้นหา ข้อผิดพลาดได้ตอน compile time

java5 แก้ไขปัญหาของ pattern นี้ โดยการนำ enum มาใช้

	public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
	public enum Orange { NAVEL, TEMPLE, BLOOD }

ความแตกต่างที่สำคัญ ของ enum ในภาษา java กับภาษาอื่นใน java enum เป็น class ในขณะที่ภาษาอื่น เช่น C, C++, and C# เก็บข้อมูลเป็น int ลักษณะของ enum ในภาษา java คือเป็น class ที่ export instance ของแต่ละ constanct ที่ประกาศใน enum นั้นโดยทาง “public static final field”

1. type safety
เราสามารถจะ assign ค่าที่ประกาศไว้ใน enum เท่านั้น

2. namespaces
แก้ปัญหา named constants เพราะ enum มี namespace (ก็ชื่อของมันเอง)

3. มันไม่ได้ เอาค่า constant มาเก็บไว้แต่มันจะ reference ไปแทน
สามารถแก้ไขหรือ เพิ่ม constants โดยไม่ต้อง build class ที่เรียกใช้มันใหม่
เหมือนกับว่าตอน build มันไม่ได้เอาค่า constant มาเก็บไว้ที่ class ของมันเลยแต่จะสร้าง reference ไปหา class enum แทน

4. เราสามารถ print ชื่อ constant, value หรือค่าอะไรก็ได้ที่เกี่ยวข้องกับ constant method toString ของมันจะ return ชื่อของ constant หรือถ้าไม่ต้องการชื่อ constant เราก็ยังสามารถ override method toString ได้แล้ว get ข้อมูลของแต่ละ enum มาได้ด้วยนะครับ

5. can use == operation

6. สามารถเพิ่ม method หรือ property ที่มีความสำพันธ์กับ constant ได้

มาดูตัวอย่างกันดีกว่า
จัดกลุ่ม constant ของ Apple จากตัวอย่างข้างบน enum “Apple.java”

	FUJI(0, "ฟูจิ"), PIPPIN(1, "พิพพิน"), GRANNY_SMITH(2, "แกรนนี่ สมิท");
	private Integer appleType;
	private String description;

	Apple(Integer appleType, String description) {
		this.appleType = appleType;
		this.description = description;
	}

เริ่มด้วยการกำหนดชื่อ constant “FUJI” ส่ง parameter ไป 2 ตัวคือ value และ description ของมันไปทาง constructor เป็นการผูก constant name, value, description เข้าด้วยกัน
เพิ่ม method

	public Integer getAppleType() {
		return appleType;
	}
	public String getDescription() {
		return description;
	}

เพิ่ม method “getApples()” เพื่อเอาไว้ get instant ของ enum ทั้งหมด

	public static List getApples() {
		return Arrays.asList(Apple.values());
	}

เพิ่ม method getApple(Integer appleType)” เพื่อเอาไว้ get instant โดย value

	public static Apple getApple(Integer appleType) {
		List apples = getApples();
		for (Apple apple : apples)
			if (appleType.compareTo(apple.getAppleType()) == 0)
				return apple;
		throw new AssertionError("Unknown Apple type : " + appleType);
	}

มาลอง test กันดีกว่า “Test.java”
สามารถ get instanct ทั้งหมดได้

	List apples = Apple.getApples();
	for (Apple apple : apples)
		log.debug(apple);

สามารถ get ค่าอื่นๆที่มีความสำพันธ์กับ constant ได้

	Apple apple1 = Apple.FUJI;
	log.debug(apple1);
	log.debug(apple1.getAppleType());
	log.debug(apple1.getDescription());

สามารถ get instanct โดย value ของมันได้

	Apple apple2 = Apple.getApple(0);

สามารถใช้ operation == ได้

	log.debug(apple1 == apple2);
Categories: Java

ClassNotFoundException: org.hibernate.hql.ast.HqlToken on OC4J

กรกฎาคม 26, 2009 iknight ใส่ความเห็น

เจอ exception นี้ตอนที่ลองหัด spring แล้วเขียน hql qurey ข้อมูลขึ้นมา
เขียน unitTest ก็ใช้งานได้ตามปกตินะไม่มีปัญหาอะไร
แต่พอลองเรียกจาก Controller ดันมาเจอ exception นี้

org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken

ก็เลยลองถามอาจารย์กูดู สรุปว่า
เกิดจากการ conflicts กันระหว่าง libraries TopLink กับ libraries Hibernate

การแก้ปัญหาก็คือเอา libraries ของ TopLink ออก
โดยการแก้ไข file orion-application.xml ของ application โดยเพิ่ม tag

<imported-shared-libraries>
	<remove-inherited name="oracle.toplink"/>
</imported-shared-libraries>

แต่ปัญหานี้ก็ยังไม่จบนะครับ เพราะทุกครั้งที่ publish มันก็จะลบ application
ออกแล้วเราก็จะได้ orion-application.xml ใหม่ (ก็คือเป็นเหมือเดิม)

การแก้ไขก็ แก้ไขที่ Configure Class Loading
Example: Removing an Oracle Shared Library at Deployment Time
จะทำให้ทุกครั้งที่ publish จะได้มันจะได้ไม่ import libraries ของ TopLink
ไปด้วยครับ

Categories: Uncategorized

Use interfaces only to define types

กรกฎาคม 19, 2009 iknight ใส่ความเห็น

ก็เป็นที่รู้ๆ กันอยู่แล้วนะครับ variable ของ interface เป็น public static final เสมอ
เพียงแค่ ประกาศแบบนี้

	String CONSTANT_VALUE = "constantValue";

มันก็จะเป็น

	public static final String CONSTANT_VALUE = "constantValue";

ด้วยเหตุที่มันเป็น final เสมอเราก็ต้อง assign ค่าให้มันเสมอ อีกเช่นกัน
(ดูดิมันช่างเหมาะจะเอาไว้เก็บ constant จริงๆ)

แล้ว java ก็ extends ได้ 1 class แต่ implements ได้หลาย interface
มันก็ดูจะเข้าท่าดีนะที่จะเขียน interface ไว้เก็บ constant เพราะเวลาเรา
implements interface นี้แล้ว ก็สามารถใช้ constant ใน interface ได้ทันที
subclass ก็สามารถใช้ได้ทันทีเช่นกัน และยังสามารถ extends class อื่นได้อีก

มันจึงเกิด pattern (antipattern) หนึ่ง ชื่อว่า interface constant

ลักษณะก็จะมีแต่ property และไม่มีการประกาศ method ให้ class ที่
implement ไปต้อง implements อะไรเลย class ที่จะใช้ constant
ก็ implements constant interface และเพื่อจะหลีกเลี่ยงการอ้าง
ถึง constant ด้วย namespace

public interface PhysicalConstants {
	static final double AVOGADROS_NUMBER = 6.02214199e23;
	static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
}

“The constant interface pattern is a poor use of interfaces.”

ถ้าดูให้ดีแล้วนะครับถ้า class ที่ implements constant interface ไม่ได้เป็น final (ซึ่ง final class ก็เป็นอะไรที่ไม่ควรเขียนอีก) ซึ่งมันอาจจะถูก extends ได้อีก sub class ของมัน ก็สามารถอ้าง constant interface ได้ แล้วถ้าวันหน้า class ที่ implements นี้มาโดยตรงไม่จำเป็นต้องใช้ constant นี้แล้ว !!แต่ก็ยังต้อง implements อยู่ดีเพราะ sub class ของมันอาจจะใช้ constant อยู่

แล้วขณะที่บาง sub class ไม่จำเ็ป็นต้องใช้ constant
ก็จะสามารถอ้างถึง constant ได้ทั้งที่ไม่จำเป็น

ถ้าต้องการใช้ constant ทางเลือกคือ

เขียน utilities class เพื่อเก็บ constant แล้วหลีกเลี่ยงการอ้างถึง constant
ด้วย namespace โดยใช้ static import

import static PhysicalConstants.*;
public class Test {
	double atoms(double mols) {
		return AVOGADROS_NUMBER * mols;
	}
}

หรือถ้ามันควรจะอยู่ที่ interface ก็ได้ถ้ามองว่า class ที่ implements นี้ไป
ควรใช้ constant เหมือนกัน (แต่ให้คิดว่าใช้ interface เป็นการประกาศชนิดของ class ก่อนส่วนจะมี constant มันก็เป็นอีกเรื่องหนึ่ง ไม่ใช่เขียน interface เพื่อที่จะเก็บ constant ก่อน )

“interfaces should be used only to define types.”
They should not be used to export constants.

reference : Effective Java

Categories: Java

Get start Spring with Hibernate

กรกฎาคม 11, 2009 iknight ใส่ความเห็น

ก่อนอื่นอ่านเรื่อง DI จากเวปนี้ก่อนนะครับ
Inversion of Control Containers and the Dependency Injection pattern

Librarise :
aopalliance.jar
aspectjrt.jar
aspectjweaver.jar
cglib-nodep-2.1_3.jar
commons-*.jar
dom4j-1.6.1.jar
hibernate3.jar
hibernate-*.jar
junit.jar
log4j-1.2.13.jar
ojdbc14.jar
spring-*.jar

Database : Oracle 10g

เริ่มต้นด้วย การ configure pool “Datasource” กันเลยดีกว่า
Spring ไม่มี pool data source นะครับ เราก็เลยต้องไปใช้ data source
ของ Jakarta Commons ที่ชื่อว่า BasicDataSource หรือจะใช้ ComboPooledDataSource ก็ได้นะครับ
Spring มี connection 2 อันนะครับ คือ
1. DriverManagerDataSource จะ return connection ใหม่ทุกครั้งที่มีการเรียกใช้
2. SingleConnectionDataSource มี connection อันเดียว ทุกครั้งที่เรียกจะได้ connection อันเดิมเสมอ
(เขียนไปงั้น ไม่น่าใช้ทั้งคู่อะ)

ตัวอย่างผมใช้ BasicDataSource นะครับ

<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
	<property name="url" value="jdbc:oracle:thin:@192.168.1.101:1521:orcl" />
	<property name="username" value="xxxx" />
	<property name="password" value="xxxx" />
	<property name="initialSize" value="5" />
	<property name="maxActive" value="10" />
</bean>

ค่าที่ set ให้กับ property ก็เหมือนกับการที่ set ให้กับ connection pool ทั่วไปนะครับ

“sessionFactory” ขอยกตัวอย่างโดยการใช้ xml mapping file ธรรมดา
เราก็ต้องใช้ LocalSessionFactoryBean ของ spring ในการสร้าง sessionFactory

<bean id="sessionFactory"
	class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mappingResources">
		<list>
			<value>domain/Signon.hbm.xml</value>
		</list>
	</property>
	<property name="hibernateProperties">
		<props>
			<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
		</props>
	</property>
</bean>

โดยจะ inject dataSource ที่เราพึ่งสร้างไปให้มันด้วย
property mappingResources : เป็น List เอาไว้กำหนด path ของ
mapping files ที่ต้องการให้มัน map Domain Class กับ Table
property hibernateProperties : เป็น prop เอาไว้กำหนดค่า config ต่างของ hibernate session

“hibernateTemplate” หน้าที่หลักของ hibernateTemplate
คือ open,close hibernateSession และแปลง hibernateException เป็น
Data access Exception ของ Spring ที่เป็น uncheck Exception ทั้งหมด

<bean id="hibernateTemplate"
	class="org.springframework.orm.hibernate3.HibernateTemplate">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

inject sessionFactory เข้าไปให้มัน

Table ที่ใช้เอามาจาก ตัวอย่าง jpetstore ของ spring ชื่อ Table “signon”
ผมมาแก้ไขนิดหน่อย โดยเพิ่ม field signon_gen เป็น surrogate key
(ไม่เกี่ยวกันตัวอย่างที่ผมจะทำหลอกนะครับ เพียงแต่เห็น Table ไหนไม่มี
surrogate key แล้วมันขัดใจยังไงไม่รู้)
Domain Class “Signon.class”

package domain;
public class Signon implements java.io.Serializable {
	private Long signonGen;
	private String username;
	private String password;
	public Signon() {
	}
	public Signon(String username, String password) {
		this.username = username;
		this.password = password;
	}
	// stripped out the accessor method and mutator method
}

Hibernate XML Mappings “signon.hbm”

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="domain.Signon" table="SIGNON" schema="SYSTEM">
	<id name="signonGen" type="java.lang.Long">
		<column name="SIGNON_GEN" precision="22" scale="0" />
		<generator  class="assigned"  />
	</id>
	<property name="username" type="java.lang.String">
		<column name="USERNAME" length="25" not-null="true" />
	</property>
	<property name="password" type="java.lang.String">
		<column name="PASSWORD" length="25" not-null="true" />
	</property>
</class>
</hibernate-mapping>

Data Access Object (DAO) “SignonDao.class”,”SignonDaoImpl.class”

package dao;
public interface SignonDao {
	public Signon findByUsername(String username) ;
}
package dao;
// stripped out the import statement
public class SignonDaoImpl extends HibernateDaoSupport implements SignonDao {
	public Signon findByUsername(String username) {
		String hql = " from Signon s where s.username = :username ";
		List signons = (List)
			getHibernateTemplate().findByNamedParam(hql, "username", username);
		return signons != null ? signons.get(0) : null;
	}
}

DAO นี้มี method เดียวนะครับ คือ findByUsername เอาไว้ค้นหา User จาก username
ตัวอย่าง เขียน hql ค้นหา class Signon where ด้วย username
แล้ว getHibernateTemplate ที่ได้มาจากการ extends HibernateDaoSupport ของ Spring
แล้วใช้ method findByNamedParam จาก hibernateTemplate ส่ง parameter ไป 3 ตัว คือ
1. hql : hql
2. “username” : ชือ parameter ใน hql ที่ต้องการ binding parameter
3. username : value ที่ต้องการ binding
จะได้ return กลับมาเป็น List ของ Object แล้วก็มา cast เป็น List<Signon>

สร้าง instance signonDao

<bean id="signonDao" class="dao.SignonDaoImpl">
	<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

โดยส่ง hibernateTemplate เข้าไปด้วย
หรือจะฉีด sessionFactory เข้าไปใน class ที่ extends HibernateDaoSupport
เลยก็ได้นะครับ ตอนนี้เราก็มี Dao พร้อมใช้งานแล้วครับ
(class ที่ extends มาจาก HibernateDaoSupport จะได้รับการสืบทอด ็็setHibernateTemplate,setSessionFactory มาด้วย )

Data Access Context “application-data.xml”
เสร็จแล้วหน้าตาของ context ของ Data access Layer จะมีหน้าตาแบบนี้นะครับ

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<!-- config data source and hibernate session -->
<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
	<property name="url" value="jdbc:oracle:thin:@192.168.1.101:1521:orcl" />
	<property name="username" value="xxxx" />
	<property name="password" value="xxxx" />
	<property name="initialSize" value="5" />
	<property name="maxActive" value="10" />
</bean>
<bean id="sessionFactory"
	class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mappingResources">
		<list>
			<value>domain/Signon.hbm.xml</value>
		</list>
	</property>
	<property name="hibernateProperties">
		<props>
			<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
		</props>
	</property>
</bean>
<bean id="hibernateTemplate"
	class="org.springframework.orm.hibernate3.HibernateTemplate">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- config data source and hibernate session -->
<!-- declare DAO -->
<bean id="signonDao" class="dao.SignonDaoImpl">
	<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<!-- declare DAO -->
</beans>

มาถึงตอนนี้ resource ของ Data access Layer ก็เสร็จหมดแล้วนะครับ
มาต่อกันที่ Service Layer ดีกว่า

Service Object (หรือ BO) “UserService .class”,”UserServiceImpl .class”

package service;
public interface UserService {
	public Signon signon(String userName, String password);
}
package service;
public class UserServiceImpl implements UserService {
	SignonDao signonDao;
	public UserServiceImpl(SignonDao signonDao) {
		this.signonDao = signonDao;
	}
	public Signon signon(String userName, String password) {
		if (GenericValidator.isBlankOrNull(username))
			throw new IllegalArgumentException();
		if (GenericValidator.isBlankOrNull(password))
			throw new IllegalArgumentException(); 

		Signon signon = signonDao.findByUsername(username);
		return signon != null && signon.getPassword().equals(password ) ? signon : null ;
	}
}

Service นี่ก็มี method เดียวเหมือนกัน คือ signon
ก่อนอื่นก็ validate ก่อนเลยนะครับ
แล้วก็ส่ง username ไปค้นหา Object Signon return ออกไป

transactionManager:

<bean id="transactionManager" class="orm.hibernate3.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

สร้าง instance ของ HibernateTransactionManager โดยส่ง sessionFactory เข้าไป
(instance เดียวกับ ที่ฉีดเข้าไปใน HibernateTemplate )

tag tx:advice:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="signon" propagation="REQUIRED" />
	</tx:attributes>
</tx:advice>

tx:method ใช้กำหนดรายละเอียดของ Transection ของแต่ละ Method

tag aop:config:

<aop:config>
	<aop:pointcut id="userServiceOperation"
		expression="execution(* *..UserServiceImpl.*(..))" />
	<aop:advisor pointcut-ref="userServiceOperation" advice-ref="txAdvice" />
</aop:config>

pointcut ใช้ AspectJ ประกาศ expression ที่จะ control Transection

userService:

<bean id="userService" class="service.UserServiceImpl">
	<constructor-arg ref="signonDao" />
</bean>

สร้าง instance UserServiceImpl ส่ง signonDao เข้าไป

Service Context “application-service.xml”
เสร็จแล้วหน้าตาของ context ของ Service Layer จะมีหน้าตาแบบนี้นะครับ

<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx

	http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- declare transection -->
<bean id="transactionManager" class="orm.hibernate3.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="signon" propagation="REQUIRED" />
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut id="userServiceOperation"
		expression="execution(* *..UserServiceImpl.*(..))" />
	<aop:advisor pointcut-ref="userServiceOperation" advice-ref="txAdvice" />
</aop:config>
<!-- declare transection -->

<!-- declare service -->
<bean id="userService" class="service.UserServiceImpl">
	<constructor-arg ref="signonDao" />
</bean>
<!-- declare service -->
</beans>

UnitTest “UnitTest.class”

package test;
public class UnitTest {
	Logger log = LogManager.getLogger(this.getClass());
	@Test
	public void test() {
		String[] contextFile = { "application-data.xml", "application-service.xml" };
		ApplicationContext context = new ClassPathXmlApplicationContext(contextFile);
		UserService userService = (UserService) context.getBean("userService");
		Signon signon = userService.signon("j2ee", "j2ee");
		log.debug(signon.getUsername() + signon.getPassword());
	}
}

กำหนด context file ของ spring ที่จะใช้งาน
create instance ClassPathXmlApplicationContext ส่ง array ที่เก็บ ชื่อของ context file เข้าไป
(ClassPathXmlApplicationContext มันจะไปหา file ที่ส่งเข้าไปจาก classPath)
return ออกมาเป็น ApplicationContext แล้วก็ Get Bean ที่ต้องการใช้งาน

Categories: Spring

Favor composition over inheritance

เมษายน 18, 2009 iknight ใส่ความเห็น

Inheritance is a powerful way to achieve code reuse,
but it is not always the best tool for the job.
Used inappropriately, it leads to fragile software.

ตอนแรกว่าจะยกตัวอย่างจาก Effective Java แต่อ่านแล้วงงๆ อ่านยาก
ตัวอย่างอ่านแล้วไม่ค่อยเห็นภาพเท่าไหร่ เลยเอาตัวอย่างจาก Head First Design Pattern ดีกว่า

เป็น ตัวอย่างที่อธิบายเรื่อง Strategy Pattern แต่เนื้อหาพูดถึงเรื่อง การใช้
composition แทนการใช้ inheritence ได้ดีทีเดียว ผมจะ focus เรื่องการใช้
composition แทน inheritance ยังไง และทำไมการใช้ inheritance
ถึงไม่สมควรทำ(จริงๆแล้ว พื้นฐานการออกแบบก็สำคัญกว่า Pattern ต่างอยู่แล้วหละครับ)

ตัวอย่าง พูดถึง duck simulation game ที่เป็ดมีความสามารถหลากหลาย
เช่น swim,quack การออกแบบ เริ่มต้นคือการ เขียน superclass เป็น class
ต้นแบบของเป็ด(Duck) แล้วก็ให้เป็ดแต่ละชนิด extends ไป

public abstract class Duck {
abstract void display();
	public void quack() {
	}
	public void swim() {
	}
}

ต่อมาก็มีความต้องการให้เป็ด บินได้ ก็ไม่ยากอะไรครับ ก็เพิ่ม method fly
ที่ Class Duck,subclass ที่ extends ไปก็ได้รับการ สืบทอด method fly

	public void fly() {
	}

ต่อมาก็มีความต้องการ เป็ดตัวใหม่ ก็ไม่น่าจะยากอะไรครับ ก็ extends Class Duck ไป
แต่เป็ดที่ต้องการเป็น “robber duckies”(robber duckies เป็นเป็ดที่ ร้องไม่ได้ )
ปัญหาก็เริ่มเกิดแล้วครับ เพราะ เป็ดทุกตัวที่ extends Duck จะได้รับการ สืบทอด method quack

หรือแม้กระทั่ง method fly ที่พึ่งเพิ่มเข้าไป subclass ของ Duck ก่อนหน้านี้
ก็ไม่เคยมีความต้องการ method fly เลย

” เมื่อคุณเพิ่ม method ที่ super class ก็เท่ากับว่าคุณเพิ่ม method ที่ไม่สมควรให้กับ บาง subclass “

“What he thought was a great use of inheritance for the
purpose of reuse hasn’t turned out so well when it comes to maintenance “

ทำไงดี ก็ต้องไป overide method ที่ไม้ต้องการ ให้มันไม่ต้องทำงานอะไร
ก็ดูเหมือนดีนะครับแต่แค่คิดก็เหนื่อยแล้วครับ ต้องทำ subclass ทุกตัวที่
extends Duck (เป็ดตัวไหนไม้ต้องการให้ทำอะไรก็ตาม overide เอา)

	@Overide
	public void fly(){
		//...
	}

ถ้ามีเป็ด 5 ตัวที่บินไม่ได้ ก็ต้อง copy paste ไปทุกตัวก็เริ่ม douplicated code

ทำไงดี สร้าง interface สำหรับ method ที่บาง subclass ไม่ต้องการ
แล้วถ้า subclass ไหนต้องการ method นี้ก็ให้ implement ไป

public abstract class Duck {
	abstract void display();
		public void swim() {
	}
}
public interface FlyAble {
	public void fly();
}
public interface QuackAble {
	public void quack();
}

เป็ดทุกตัวต้อง extends Duck แล้วถ้าตัวไหนต้องการให้ fly หรือ quack
ก็ implement FlyAble หรือ QuackAble เอาครับ

ทำแบบนี้ก็ดูเหมือนดีนะครับ แต่ลองคิดดูถ้าเป็ดตัวไหนมีพฤติกรรมการบินที่เหมือนกัน
ก็ต้อง implement method fly เหมือนกัน และมี code เหมือนกัน

public class MallardDuck extends Duck implements FlyAble {
	public void fly(){
		// same perform fly
	}
}
public class RedheadDuck extends Duck implements FlyAble {
	public void fly(){
  		// same perform fly
	}
}

วิธีนี้ทำให้ ไม่สามารถ reuse code ได้นะครับ แต่ที่แย่กว่า คือ douplicated code
ถ้าพฤติกรรมการบินแบบนี้เปลี่ยน ก็ต้องตามแก้ ทุก subclass
“Identify the aspects of your application
that vary and separate them from what stays the same”

ทำไงดี เขียน interface FlyBehavior แล้วก็ให้ fly แต่ละชนิด implements ไป

public interface FlyBehavior {
	public void   fly();
}
public class FlyNoWay implements FlyBehavior {
	public void fly() {
    		System.out.println("I can't fly");
	}
}
public class FlyRocketPowered implements FlyBehavior {
	public void fly() {
		System.out.println("I'm flying with a     rocket");
	}
}

class Duck ก็ถือ reference ของ FlyBehavior แล้วก็เขียน setFlyBehavior
เพื่อรอรับ instance ของ class ที่ implements FlyBehavior ไป
เวลาจะใช้ FlyBehavior ไหนก็ set ให้กับ class Duck

“Program to an interface, not an implementation”

public abstract class Duck {
	FlyBehavior flyBehavior;
	public void setFlyBehavior (FlyBehavior fb) {
		flyBehavior = fb;
	}
	public void performFly() {
		flyBehavior.fly();
	}
}

เสริมนิดๆ อย่างให้มอง interface เป็น type ของ class
เหมือนกับ ที่มอง class เป็น type ของ instance นะครับ
ตรงนี้สำคัญนะครับ จะทำให้ไม่สับสนการเลือกใช้ ระหว่าง
interface กับ abstact class อืม อ่านแล้วงงๆ เดี๋ยวมาเล่าต่อ

การถือ reference ของ FlyBehavior นี้หละครับคือการ composition
การได้มาของ method fly มาจากการที่ FlyBehavior เป็นส่วนประกอบของ
Duck ไม่ใช้ ได้รับจากการสืบทอด

จริงๆแล้ว การเขียน แบบ composition จะสามารถ reuse ได้มากกว่านะครับ
คือถ้าเราเขียน แบบ composition ก็เหมือนกับว่าเราเขียนโปรแกรมเป็น
componance เราสามารถเอา componance เหล่านี้ไป reuse ได้
เรียกว่า componance reuse ไม่ใช้ code reuse
spring ก็ promote การเขียนโปรแกรมให้เป็น componance ด้วย DI

แล้ว dependency ระหว่าง class ก็น้อยกว่ามากครับ
แล้ว code ก็เข้าใจง่ายกว่าด้วยนะครับ

“Favor composition over inheritance”

เขียนไป เขียนมาไม่รู้จะเข้าใจหรือปล่าว เอาว่าน่าจะเห็นประโยชน์ของการใช้ composition แทนการใช้ inheritance บ้างนะครับ

reference :
Effective Java(แค่ประโยคแรกครับ อ่านแล้วชอบเลยเอามาแปะไว้)
Head First Design Pattern

Categories: OOAD

Row Data Gateway

มีนาคม 22, 2009 iknight ใส่ความเห็น

22-3-2552-20-59-261

ลักษณะของ Object จะมี method insert, update, delete เพื่อทำงานกับ Table ได Table หนึ่ง หรือ view ได view หนึ่ง และมีโครงสร้างข้อมูลเหมือนกับ row ใน table โดยแต่ละ column จะเป็น attribute ใน object แต่ละ instance จะเก็บข้อมูล 1 row ใน table หรือ view (ก็คล้ายๆกับ Table Data Gateway อะครับมี method insert, update, delete เหมือนกัน เพียงแต่ว่า Row Data Gateway จะเก็บข้อมูลด้วย ก็เหมือนกับเอา domain class กับ Table Data gateway มารวมกัน) โดย pattern นี้จะต้องมี finder object เอาไว้ค้นหาข้อมูล เพราะ method find ไม่ควรอยู่ใน Row Data Gatway (instance ของ Row Data Gatway จะเกิดได้ขึ้นก็ควรมีข้อมูล จาก row ใน base แล้ว)

ถ้าดูให้ดีแล้วนะครับมันก็เท่ากับว่าเอา Data Access Logic ไปใส่ไว้ใน domain class
แล้วก็เขียน finder object ขึ้นมาเพื่อค้นหาข้อมูล ซึ่งก็เท่ากับว่าการใช้ pattern นี้ก็เหมือนกับบังคับให้ใช้ Value Object เพื่อส่งข้อมูลไป presentation layer เพราะ Data Access Logic ไม่ควรไปอยู่ที่ presentation layer

อย่าสับสนระหว่าง Row Data Gateway กับ Rich Domain Model นะครับ
ความแตกต่างชัดเจนคือ Row Data Gateway เป็น anemic domain ที่ใส่
Data Access Logic ลงไป แล้วเอา Business Logic ไปไว้ที่ Transaction Script
ในขณะที่ Rich Domain Model เป็น domain ที่เก็บข้อมูลและใส่ Business Logic
ลงไป แล้วเอา Data Access Logic เอาไปไว้ที่ Data Mapper

Data Access Layer Business Layer include
Date Source layer Domain Layer
Table Data Gateway Transaction Script Anemic Domain
Row Data Gateway Transaction Script Anemic Domain + Value Object
Data Mapper Rich Domain Value Object

Rich Domain Model หาอ่านเอาใน PEAA นะครับเรื่อง Domain Model นั้นหละครับ
Domain Model ของ martin flower rich เสมอไม่มี Anemic Domain Model เลยไม่ได้เขียนถึง แต่ไปเขียนใน bliki ว่า Anemic Domain Model เป็น anti-patterns (กำ ผมก็ใช้อยู่)

แนะนำให้อ่าน PEAA ของ martin flower นะครับมี Pattern ของ Enterprise Application ให้เลือกใช้มากมาย และที่พูดคุยกันในเว็บบอร์ดทั่วไปถ้าพูดถึง Pattern ในหนังสือเล่มนี้มักจะไม่ค่อยอธิบายกันส่วนมากแนะให้ไปอ่านกันเอง (ราวกับว่าทุกต้องมียังไงอย่างนั้น) แต่ที่สำคัญมากๆๆๆ คือหนังสือเล่มนี้เก่ามากแล้วครับอ่านแล้วคนอ่านก็จะเก่าไปด้วยเลยครับ บางอย่างก็มีคนเอามา implement แล้ว Hibernate, EJB, Spring, Struts
ซึ่งก็รู้สึกว่าถ้าได้ใช้ tecnology อยู่แล้วก็ไม่จำเป็นต้องอ่านก็ได้มั้ง (ขี้เกียจอ่าน) หรือจะว่าก็ดีเหมือนกันจะได้ไม่ใช้ tecnology ในทางที่ผิดๆ แต่ก็จะได้รู้ pattern ที่จำเป็นต้องรู้ เช่นเรื่อง Concurrency, Lazy Load แบบดั่งเดิมเป็นยังไง, Money Pattern จะได้คิดตังไม่ผิด

ส่วนผมไม่ได้อ่านทั้งหมดเอาเป็น reference มากกว่า อ่านเท่าที่จำเป็นจำเท่าที่จำได้
มิงั้นตั้งหน้าตั้งตาตะบันอ่านมีหวังหลับแน่นอน ไว้คุ้นๆจะใช้แล้วค่อยมาอ่านดีกว่า

กลายเป็นเชียร์ให้ซื้อหนังสือไปซะงั้น ได้ไงก็ไม่รู้(พิมพ์เพลิน)
reference : PEAA

Categories: Pattern

Table Data Gateway

มีนาคม 18, 2009 iknight ใส่ความเห็น

21-3-2552-15-45-49

Table Date Gateway คือ Object ที่ไว้จัดการกับ Database (CRUD) โดยลักษณะของ Object จะมี method find, insert, update, delete เพื่อทำงานกับ Table ได Table หนึ่ง หรือ view ได view หนึ่ง โดยแต่ละ method จะ map input parameter ใส่ SQL แล้วสั่ง excute การทำงานจะเป็นแบบ stateless คือไม่เก็บสถานะไว้ทำงานครั้งเดียวจบ ลักษณะการทำงานการเรียก function ส่วนมากแล้วเวลาใช้ pattern นี้จะใช้ 1 Object ต่อ 1 Table แต่จริงแล้ว สามารถใช้ 1 Object ต่อ 1 view ที่สนใจ หรือ 1 Object ต่อ Table ทั้งหมดใน base ก็ได้ แต่ที่แน่ๆ ใช้ 1 Object ต่อ 1 Domain Class (anemic domain นะ มิใช่ rich domain) หน้าที่หลักของ Table Date Gateway คือจัดการกับ Data Access Logic ไม่ควรมี Business Logic ปน (เคยอ่านเจอว่า สามารถมี Business ปนได้ แต่เท่าที่จำเป็น) แต่ผมว่าไม่ควรมีเลยมากกว่า ยังไงก็แล้วแต่สดวกครับงานใครงานมัน ถ้ามีแล้วทำงานง่ายขึ้น ประสิทธิภาพดีขึ้นก็แล้วแต่ แต่อย่าลืมว่า Table Date Gateway ต้อง Focus การทำงานที่ Data Access Logic

reference : PEAA

Categories: Pattern