2009年12月25日 星期五

2009年12月14日 星期一

2009年12月7日 星期一

Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream

小胖教我的
eclipse開發時, 用本機無法寄mail
當出現下面exception時
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream


C:\Program Files\MyEclipse 6.5\myeclipse\eclipse\plugins\com.genuitec.eclipse.j2eedt.core_6.5.0.zmyeclipse650200806\data\libraryset\EE_5\javaee.jar

把javaee.jar裡的
javax\activation\
javax\mail\
刪掉

clean eclipse  , build eclipse

2009年11月25日 星期三

2009年11月6日 星期五

編碼

我對編碼的認識, 就放這囉, 大多是從網路收集整理低


以前電腦的編碼 只有8位

Unicode是由於傳統的字元編碼方式的侷限性而產生的,例如 ISO 8859 所定義的字元雖然在不同的國家中廣泛地使用,可是在不同國家間卻經常出現不相容的情況。
在文字處理方面,Unicode的功用是為每一個字元提供一個唯一的代碼(即一組數字),而不是一種字形

為了使Unicode與已存在和廣泛使用的舊有編碼互相兼容,尤其是差不多所有電腦系統都支援的基本拉丁字母部分,
所以Unicode 的首256字元仍舊保留給ISO 8859-1 所定義的字元,使既有的西歐語系文字的轉換不需特別考量

在表達一個 Unicode 的字元時,通常會用「U+」然後緊接著一組十六進位的數字來表示這一個字元。







補充:
在基本多文種平面(Basic Multilingual Plane,簡稱 BMP)
裏的所有字元,只要使用四位十六進制數(例如 U+4AE0,共支持六萬多個字元)來表示,但在 BMP 以外的字元則需要使用五位或六位十六進制數了。


ASCII就只包含拉丁字母
ISO 8859-1(Latin-1) 是個8位字符集,它以ASCII為基礎,在空置的0xA0-0xFF的範圍內,加入192個字母及符號
Unicode (這只是一種編碼方式, 非實現) : 使用16位的編碼空間。也就是每個字元佔用2個位元組。這樣理論上一共最多可以表示 2的16次方 , 即 65536 個字元
    unicode的實現 :
        
    1.UTF-8 (Unicode 的實現方式稱為Unicode轉換格式 Unicode Translation Format,簡稱為 UTF)
        如果一個僅包含基本7位ASCII字元的 Unicode 文件,如果每個字元都使用2位元組的原 Unicode 編碼傳輸,其第一位元組的8位始終為0。這就造成了比較大的浪費。
        對於這種情況,可以使用 UTF-8 編碼,這是一種變長編碼,它將基本7位ASCII字元仍用7位編碼表示,佔用一個位元組(首位補0)
                而遇到與其他 Unicode 字元混合的情況,將按一定演算法轉換,每個字元使用1-3個位元組編碼,並利用首位為0或1進行識別
    2.UTF-16
    3.BIG5








String sr = new URLCodec().encode("小胖", "utf-8");

2009年11月5日 星期四

正規表式示-regex-基礎

字元:
    \t Tab
    \n 換行
    \r 歸位
    \f 換頁
    \e 跳脫字元

字元類型:
    . 任意字元
    [abc] a, b, c中的任意字元 ( 同於 a | b | c)
    [^abc] 除了a, b, c中的任意字元
    [a-zA-Z] a-z或A-Z的任意字元
    [abc[def]] 聯集?
    [a-z&&[def]] 交集?
    \s 空白型的字元 (空白, 跳格, 換行, 換頁, 歸位)
    \S 非空白型的字元
    \d 指阿拉伯數字 0到9
    \D 非阿拉伯數字
    \w 字詞字元 [a-zA-Z_0-0]
    \W 非字詞字元

邏輯運算子 :
   
   
邊界比對:
    ^ 檔案起始處
    $ 檔案結尾處
    \b 字詞的邊界
    \B 非字詞邊界
    \G 前一相符處之未
   
數量飾詞:
    ? 表示一個或無
    * 零次或多次
    + 一次或多次
    {n} 符合n次
    {n,} 至少n次
    {n,m} 至少n次但不多於m次
   
群組:
    群組0代表整個表示式
    群組1表示第一個被括起來的群組
    ...   
       

樣式標記:
    有用到再貼唄






Matcher物件
    matches() 只會比對字串一開始的部份, 並全部符合regex才會成功
    lookingAt() 只會比對字串一開始的部份, 只要輸入字串開始部份符合就成功
    find() 能找出輸入字串中所有此regex存在的地方
    find(int start)
    groupCount() 回傳 群組0以外的群組數目
    group() 回傳前一次比對動作
    start() 回傳前一次比對動作中, 找到群組的開始索引值
    end() 回傳前一次比對動作中, 找到群組的最後一個字元索引值加一



方便傳入字串與regex, 測試用

下面code的作者 http://www.mindviewinc.com/TIJ4/CodeInstructions.html


//: strings/TestRegularExpression.java
// Allows you to easily try out regular expressions.
// {Args: abcabcabcdefabc "abc+" "(abc)+" "(abc){2,}" } 
import java.util.regex.*;

public class TestRegularExpression {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage:\njava TestRegularExpression " +
"characterSequence regularExpression+");
System.exit(0);
}
System.out.println("Input: \"" + args[0] + "\""); 

for (String arg : args) {
System.out.println("Regular expression: \"" + arg + "\"");
Pattern p = Pattern.compile(arg);
Matcher m = p.matcher(args[0]);
while (m.find()) {
System.out.println("Match \"" + m.group() + "\" at positions " + 
m.start() + "-" + (m.end() - 1));
}
}
}
}


/* Output:
Input: "abcabcabcdefabc"
Regular expression: "abcabcabcdefabc"
Match "abcabcabcdefabc" at positions 0-14
Regular expression: "abc+"
Match "abc" at positions 0-2
Match "abc" at positions 3-5
Match "abc" at positions 6-8
Match "abc" at positions 12-14
Regular expression: "(abc)+"
Match "abcabcabc" at positions 0-8
Match "abc" at positions 12-14
Regular expression: "(abc){2,}"
Match "abcabcabc" at positions 0-8
*///:~

2009年11月2日 星期一

Exception 不見的情況

情況一:
lm.f()中丟出的exception, 被finally中的exception取代掉了

class VeryImportantException extends Exception {
  public String toString() {
    return "A very important exception!";
  }
}

class HoHumException extends Exception {
  public String toString() {
    return "A trivial exception";
  }
}

public class LostMessage {
  private static Test monitor = new Test();
  void f() throws VeryImportantException {
    throw new VeryImportantException();
  }
  void dispose() throws HoHumException {
    throw new HoHumException();
  }
  public static void main(String[] args) throws Exception {
    LostMessage lm = new LostMessage();
    try {
      lm.f();
    } finally {
      lm.dispose();
    }
  }
}

情況二:
若在finally直接return

參考 : http://www.mindview.net/Books/TIJ/

Java note

顯示所有作業系統的環境變數


for (Map.Entry entry: System.getenv().entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}

由誰呼叫某method
System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName());
System.out.println(Thread.currentThread().getStackTrace()[2].getMethodName());
System.out.println(Thread.currentThread().getStackTrace()[3].getMethodName());

2009年10月28日 星期三

Inner class

為什麼需要inner classes?

一般來說, inner class 會繼承某個class或實作某interface, 而且inner class內的程式碼會操作
其outer class物件. 所以也可以講, inner class所提供的其實是針對outer class的某個窗口.

但如果我只需要"指向某個interface"的reference, 為什麼不直接讓outer class實作interface就好?
若這麼做符合需求, 就這麼做. 那麼由inner class實作interface與outer class實作的區別在那呢?
後者比較沒享受到interface的便利性.所以

    每個inner class 都能夠各自extends某一個實作類別(implementation).因此, inner class不受限
    於outer class是否已extends自某一類別.
   
inner class所提供的"繼承自多個具象(concrete)或抽象(abstract)類別"的能力, 可說是多重繼承問題的解決方案.

2009年10月27日 星期二

JQuery - Radio


不知道哪個版本了, 動態的把選取的值取出
$('input:checked[name="xxx"]').val();
$("input[name='privacy.info_freq']").click(function(){ } 綁定後, 用 $(this).val() 
$("input[name=xxx][@type=radio]").attr("checked",'2'); //把位置2 的值 checked
$("input:[name='xxx']:nth(1)").attr("checked","true");
$('input[name=xxx]').get(0).checked //檢查是否選取, 回傳boolean, 也可直接 = 給值
$("#xxx").attr("disabled", "true"); //針對某id來disabled
$("input[name=xxx][@type=radio]").attr("disabled","true"); //這name的radio全部disabled
$("input[name=xxx][@type=radio]").attr("disabled",""); //這name的radio全部 enabled
1.7 的版本如下:

當radio同一個名稱, 且有好幾個的時候要如何指定當中的某一個為 checked,

注意 : 0 為第一個
    $j('input[name="role"][@type=radio]').get(0).checked = true;
    $j('input[name="role"][@type=radio]:nth(0)').attr("checked", true)
    $j('input[name="role"][@type=radio]').first().attr("checked", true);
    $j('input[id="changeRole"][@type=radio]:first').attr("checked", true);    

2009年10月23日 星期五

com.googlecode.jsonplugin.JSONException: com.googlecode.jsonplugin.JSONException

頁面上使用jquery的ajax去call struts2的action


    $.ajax({
        url: 'xxxAtion.html',
        type: 'post',
        data: {
            'id' : "todd",
        },
        dataType: 'json',
        success: function(response, status) {
            var resultMessage = response.resultMessage;
            var resultStatus = response.status;
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert("系統繁忙, 請稍後再試!");
        }
    });


在action要return回去時, 不管怎樣都是跑到error

jquery的errro回傳textStatus寫 parsererror,
但發現吐回來的content有 com.googlecode.jsonplugin.JSONException


後來原因是 action中, 由spring去注入的xxxDAO, 寫了getxxxDAO, 拿掉就可以了

參考:
出現這種情況是在使用json-plugin時,一些不需要串行化的屬性被序列化了 比如spring 注入的 services生成了getter、序列化ID生成了getter等等 ,json plugin會把有getter方法的屬性序列化,格式化為json串 。解決辦法:可以去掉getter或者在getter上加上@JSON(serialize=false)

2009年10月15日 星期四

Hibernate - Native SQL

小胖老師真厲害, 受教了~

1.left outer join



final String sql = "SELECT A.* FROM xxx A LEFT JOIN xxx B
ON A.xxx = B.xxx WHERE B.xxx = ?";

List result = getHibernateTemplate().executeFind(new HibernateCallback(){
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
List list = (List)session.createSQLQuery(sql)
.addEntity("A", MyFriendDynamic.class)
.setString(0, userId)
.list();
return list;
}
});
return result;



2. select count(*) from xxx



final String sql = "SELECT count(*) as count FROM xxx A LEFT JOIN xxx B
ON A.xxx = B.xxx WHERE B.xxx = ?";

Integer count = (Integer) getHibernateTemplate().execute(
new HibernateCallback(){
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
Integer query = (Integer)session.createSQLQuery(sql)
.addScalar("count", Hibernate.INTEGER)
.setString(0, userId)
.uniqueResult();
return query;
}
});
return count;

2009年10月1日 星期四

Jmeter 基礎設定

如何測試:
  • ~/jakarta-jmeter-2.3.3/TestPlan.jmx
  • ~/jakarta-jmeter-2.3.3/Data.txt
  • sh jmeter -n -t ~/jakarta-jmeter-2.3.3/TestPlan.jmx -l log.jtl

參考:
  • -n 這是在無界面模式運行JMeter
  • -t [包含測試計劃的JMX文件的名字]
  • -l [記錄取樣結果的JTL文件的名字]
  • -r 運行在JMeter property文件裡所有的」遠程服務器」的測試
  • -R [遠程服務器的名單]運行制定的遠程服務器的測試
  • 這個腳本也允許你指定可選的防火牆/代理服務器信息:
  • -H [代理服務器主機名或者ip地址]
  • -P [代理服務器端口]
  • 例子 : jmeter -n -t my_test.jmx -l log.jtl -H my.proxy.server -P 8000

如何分佈式測試:

服務端:
要作為Agent的電腦,必須執行JMeter的bin目錄下, jmeter-server.bat(Windows)或jmeter-server (Liunx下,Bash),這會啟動Agent的RMI服務,預設使用1099作為連接埠,您可以在Agent的電腦中JMeter的bin目錄中,找到jmeter.properties檔案中的server_port進行設置。

為開啟服務器,在每一台主機運行jmeter-server/jmeter-server.bat
jmeter -server

log:
jmeter-server.log

客戶端:
jmeter -n -t testplan.jmx -r [-Gprop=val] [-Z]
  • -G is used to define JMeter properties to be set in the servers
  • -X means exit the servers at the end of the test //測試結束就關掉server
  • -R server1,server2 - can be used instead of -r to provide a list of servers (overrides remote_hosts)

而要作為Controller的電腦,可以打開jmeter.properties檔案,找到remote_hosts選項,預設是設定為127.0.0.1,您可以設置為Agent的電腦並指定連接埠
例如:remote_hosts:192.168.0.3:1099,192.168.0.9:2010

jmeter還有好多測試種類可以選@@

好文章:
http://jakarta.apache.org/jmeter/usermanual/get-started.html
http://www.ibm.com/developerworks/cn/opensource/os-pressiontest/
http://www.cnblogs.com/jackei/archive/2006/11/13/558720.html

2009年9月18日 星期五

tomcat設定

tomcat設定


1.若要用jconsole去連Tomcat時
JAVA_OPTS="-Xmx4096M -Xmx4096M -Dfile.encoding=MS950

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9004
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

1.判斷瀏覽器
function getOs()
{
if(navigator.userAgent.indexOf("MSIE")>0)return 1;
if(isFirefox=navigator.userAgent.indexOf("Firefox")>0)return 2;
if(isSafari=navigator.userAgent.indexOf("Safari")>0)return 3;
if(isCamino=navigator.userAgent.indexOf("Camino")>0)return 4;
if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0)return 5;
return 0;
}

2009年9月1日 星期二

Java-接收郵件

spring & jakarta-common-mail 已提供很好的封裝在發送 mail 這方面, 但並未找到有提供接收 mail 的部份.
以下提供範例, 僅供參考


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Properties;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MailReceiver {
private static final Log log = LogFactory.getLog(MailReceiver.class);

private String host = null;
private String username = null;
private String password = null;
private String attachPath = null;

// receive
public void reveiveMail() throws Exception {

Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("pop3");
store.connect(getHost(), getUsername(), getPassword());

// default 是 inbox
Folder folder = store.getFolder("INBOX");

// can delete, 設定對信箱的操作
folder.open(Folder.READ_WRITE);

// 讀取信件
Message message[] = folder.getMessages();

// 有幾封信
int messageLength = message.length;

log.info("Messages's length: " + messageLength);

for (int i = 0; i < message.length; i++) {
// 設定對信的操作, 接收完要不要刪除
message[i].setFlag(Flags.Flag.DELETED, false);

handleMultipart(message[i]);
}

// close
if (folder != null) {
folder.close(true);
}
if (store != null) {
store.close();
}
}

// handle
private void handleMultipart(Message msg) throws Exception {
handle(msg);
String disposition;
Multipart mp = (Multipart) msg.getContent();
int mpCount = mp.getCount();
for (int m = 0; m < mpCount; m++) {

BodyPart part = mp.getBodyPart(m);
disposition = part.getDisposition();

// 處理附件
if (disposition != null && disposition.equals(Part.ATTACHMENT)) {
saveAttach(part, getAttachPath());
} else {
// 其它的物件
Object obj = part.getContent();
if (obj instanceof MimeMultipart) {
MimeMultipart mm = (MimeMultipart) obj;
showContent(mm);
}
}
}
}

private void showContent(MimeMultipart mm) {
try {
log.info("content-type : " + mm.getContentType());
int count = mm.getCount();
log.info("count : " + count);
for (int i = 0; i < count; i++) {
log.info(i + "----");
log.info(mm.getBodyPart(i).getContent());
}
} catch (MessagingException e) {
log.error(e.getMessage(), e);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}

private static void handle(Message msg) throws Exception {
log.info("郵件主題 : " + msg.getSubject());
log.info("郵件作者 : " + Arrays.toString(msg.getFrom()));
log.info("發送日期 : " + msg.getSentDate());
}

private static void saveAttach(BodyPart part, String filePath)
throws Exception {

String temp = part.getFileName();
log.info("temp file name : " + temp);

String fileName = temp;
if (temp.length() > 8 && temp.indexOf("?=") != -1) {
String s = temp.substring(8, temp.indexOf("?="));
fileName = new String(new Base64().decode(s.getBytes("big5")), "big5");
}

log.info(" get attachment : " + fileName);
InputStream in = part.getInputStream();

// save
log.info(filePath + "" + fileName);
FileOutputStream out = new FileOutputStream(new File(filePath + fileName));
IOUtils.copy(in, out);
}

public String getAttachPath() {
return attachPath;
}

public void setAttachPath(String attachPath) {
this.attachPath = attachPath;
}

public String getHost() {
return host;
}

public void setHost(String host) {
this.host = host;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public static void main(String[] args) {

MailReceiver receiver = new MailReceiver();
receiver.setHost("staff.pchome.com.tw");
receiver.setUsername("1234");
receiver.setPassword("1234");
receiver.setAttachPath("D:\\email\\");
new File(receiver.getAttachPath()).mkdirs();
try {
receiver.reveiveMail();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

2009年8月24日 星期一

Jakarta 介紹


Apache Ant Project

Apache Avalon Project
是一套面向?件的?程工程
Apache Cocoon Project
是一套XML框架


Apache DB Project
Torque
   ?
OJB
   O/R mapping
  
Apache Excalibur Project
Excalibur
  輕量的可嵌入式反向控制容器?
  
Apache Geronimo Project
Geronimo
   j2ee container ?
  
Apache Gump Project
Gump
   ?
  
Apache HTTP WebServer Project
HTTP WebServer
  
  
Apache James Project
James
  
  
Apache Logging Services Project
Log4J
  
  
Apache Maven Project
Maven
   POM(工程對象模型?)
  
Apache Portals Project
Jetspeed-1
  
Jetspeed-2
  
  
Apache Struts Project
Struts


APIs , tools, 等

BCEL
  The Byte Code Engineering Library (formerly known as JavaClass) 分析java class?
BSF
  Bean Scripting Framework (BSF),bean script框架? 讓script可以取得java object?
Commons
  Attributes
Runtime API to metadata attributes such as doclet tags.
BeanUtils
Easy-to-use wrappers around the Java reflection and introspection APIs.
Betwixt
Services for mapping JavaBeans to XML documents, and vice versa.
Chain
"Chain of Responsibility" pattern implemention.
定義執行順序
it should be feasible to utilize the Chain of Responsibility APIs in the "front controller" of a web application framework (such as Struts),
CLI
Command Line arguments parser.

參考:
http://tech.ddvip.com/2008-10/122343744475087.html
Codec
General encoding/decoding algorithms (for example phonetic, base64, URL).
Collections
Extends or augments the Java Collections Framework.
Compress
Defines an API for working with tar, zip and bzip2 files.
Configuration
Reading of configuration/preferences files in various formats.
Daemon
Alternative invocation mechanism for unix-daemon-like java code.
DBCP
Database connection pooling services.
DbUtils
JDBC helper library.
Digester
XML-to-Java-object mapping utility.
Discovery
Tools for locating resources by mapping service/reference names to resource names.
EL
Interpreter for the Expression Language defined by the JSP 2.0 specification.
Email
Library for sending e-mail from Java.
Exec
API for dealing with external process execution and environment management in Java.
FileUpload
File upload capability for your servlets and web applications.
IO
Collection of I/O utilities.
JCI
Java Compiler Interface
Jelly
XML based scripting and processing engine.
Jexl
Expression language which extends the Expression Language of the JSTL.
JXPath
Utilities for manipulating Java Beans using the XPath syntax.
Lang
Provides extra functionality for classes in java.lang.
Launcher
Cross platform Java application launcher.
Logging
Wrapper around a variety of logging API implementations.
Math
Lightweight, self-contained mathematics and statistics components.
Modeler
Mechanisms to create Model MBeans compatible with JMX specification.
Net
Collection of network utilities and protocol implementations.
Pool
Generic object pooling component.
Primitives
Smaller, faster and easier to work with types supporting Java primitive types.
Proxy
Library for creating dynamic proxies.
Sanselan
A pure-Java image library.
SCXML
An implementation of the State Chart XML specification aimed at creating and maintaining a Java SCXML engine. It is capable of executing a state machine defined using a SCXML document, and abstracts out the environment interfaces.
Transaction
Implementations for multi level locks, transactional collections and transactional file access.
Validator
Framework to define validators and validation rules in an xml file.
VFS
Virtual File System component for treating files, FTP, SMB, ZIP and such like as a single logical file system.
ECS
  The Element Construction Set ?
JMeter
  
ORO
  文本處理工具, 提供perl5.0兼容的regex, AWK-like regex, glob 表示式, 提供替換,分割,文件名稱等功能
POI
excel ?
Regexp
  
Taglibs
  jsp用
Watchdog
  檢查servlet或jsp容器執行情況
  
frameworker
Cactus
  Cactus 測試框架 ? 針對server端的java code (如servlets, EJBs, tag libraries, filters, ...)
HiveMind
  服務與配置的核心 ?
Lucene

Tapestry

Turbine

Velocity

2009年8月20日 星期四

Design Pattern - Iterator Pattern

Iterator Pattern

假設, 各種飲料店實作, 儲存資料的方式都不同時...

public class TeaBeverage{

ArrayList allTea;

public TeaBeverage{

allTea = new ArrayList();
Item item = new Item();
item.setName("紅茶");
allTea.add(item);

item = new Item();
item.setName("奶茶");
allTea.add(item);
}

public ArrayList getAllItem(){
return allTea;
}
}

public class CafeBeverage{

ArrAllCafe[] arrAllCafe;

public CafeBeverage{

arrAllCafe = new ArrAllCafe[2];

Item item = new Item();
item.setName("紅茶");
arrAllCafe[0] = item;

item = new Item();
item.setName("奶茶");
arrAllCafe[1] = item;
}

public ArrayList getAllItem(){
return arrAllCafe;
}
}


這時, 我們若要取出tea, cafe的所有資料, 它們return的類型是不同的

所以若這二個class能針對interface實現, 我們在使用時, 也針對這interface

好處:
1.把實作的儲存方式封裝起來
2.解藕


public interface IIterator{

boolean hasNext();
Object next();
}

public class CafeBeverageIterator implements IIterator{

ArrAllCafe[] arrAllCafe;
int position = 0;

public CafeBeverageIterator(ArrAllCafe[] arrAllCafe){
this.arrAllCafe = arrAllCafe;
}

public Object next(){
Item item = arrAllCafe[position];
position = position + 1;
return item;
}

public boolean hasNext(){
if(position >= arrAllCafe.length || arrAllCafe[position] == null){
return false;
}else{
return true;
}
}
}


修改原本的CafeBeverage, 改成回傳Iterator interface

public class CafeBeverage{

//同上

//public ArrayList getAllItem(){
//return arrAllCafe;
//}

public IIterator createIterator(){
return CafeBeverageIterator(arrAllCafe);
}
}


未完

2009年8月18日 星期二

Lang-其它好用的 Utils

lang.time 底下好用的 Utils (org.apache.commons.lang.time)

// 將日期轉為字串
Date date1 = new Date();
String formatDate = DateFormatUtils.format(date1, "yyyy-MM-dd");
System.out.println(formatDate);

// 將字串轉為日期
Date date2 = DateUtils.parseDate(formatDate, new String[] {"yyyyMMdd", "yyyy-MM-dd" });
System.out.println(date2);

// 只有比較日期, 沒有比較時間, 所以會回傳 true
boolean isSameDay = DateUtils.isSameDay(date1, date2);
System.out.println(isSameDay);


lang.builder 底下好用的 Utils (org.apache.commons.lang.builder)
#) EqualsBuilder 要 override equals 時,

public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
MyClass rhs = (MyClass) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.append(field3, rhs.field3)
.isEquals();
}
// or
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}



#) HashCodeBuilder 要 override hashCode 時,

public class Person {
String name;
int age;
boolean smoker;
...

public int hashCode() {
// you pick a hard-coded, randomly chosen, non-zero, odd number
// ideally different for each class
return new HashCodeBuilder(17, 37).
append(name).
append(age).
append(smoker).
toHashCode();
}
}
// or
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}


#) ToStringBuilder 要看物件裡有什麼內容時,
1. override toString()

public class Person {
String name;
int age;
boolean smoker;

...

public String toString() {
return new ToStringBuilder(this).
append("name", name).
append("age", age).
append("smoker", smoker).
toString();
}
}

2. 直接將 Object 印出來

Person P = new Person();
p.setName("hank");
...
ToStringBuilder.reflectionToString(p);
// or
ToStringBuilder.reflectionToString(ToStringStyle.MULTI_LINE_STYLE, p);

Lang-StringUtils

Jakarta 中 的 common-lang, 提供許多 java.lang.* 額外的 methods, 這次先說明 StringUtils 的一些常用的範例.


import org.apache.commons.lang.StringUtils;


public class StringUtilsDemo {

/**
* 1. Checks if a String is whitespace, empty ("") or null. (判斷 string 是否是空白, "" 或 null)
*/
public static void demoBlank() {
String str = " ";
System.out.println(StringUtils.isBlank(str)); // true

str = " abc ";
System.out.println(StringUtils.isBlank(str)); // false

str = " "; // 全形
System.out.println(StringUtils.isBlank(str)); // true

str = null;
System.out.println(StringUtils.isBlank(str)); // true
// 如果用 StringUtils.isNotBlank() <-- 則以上結果會相反
}

/**
* 1. Checks if a String is empty ("") or null. (判斷 string 是否是 "" 或 null, 與
* blank 的差別在於 whitespace )
*/
public static void demoEmpty() {
String str = " ";
System.out.println(StringUtils.isEmpty(str)); // false

str = " abc ";
System.out.println(StringUtils.isEmpty(str)); // false

str = " "; // 全形
System.out.println(StringUtils.isEmpty(str)); // false

str = null;
System.out.println(StringUtils.isEmpty(str)); // true
// 如果用 StringUtils.isNotEmpty() <--則以上結果會相反
}

/**
* 1. Compares two Strings, returning true if they are equal. (比較2個字串,
* 回傳是否相等) 2. nulls are handled without exceptions. (當 null 時, 不會發生
* exception) 3. Two null references are considered to be equal. (皆為 null 時,
* 則認為是相同的.) 4. The comparison is case sensitive. (大小寫有差別)
*/
public static void demoEquals() {
System.out.println(StringUtils.equals(null, null)); // true
System.out.println(StringUtils.equals(null, "abc")); // false
System.out.println(StringUtils.equals("abc", null)); // false
System.out.println(StringUtils.equals("abc", "abc")); // true
System.out.println(StringUtils.equals("abc", "ABC")); // false
}

/**
* 與 StringUtils.equals 的差別在於呼略大小寫
*/
public static void demoEqualsIgnoreCase() {
System.out.println(StringUtils.equalsIgnoreCase(null, null)); // true
System.out.println(StringUtils.equalsIgnoreCase(null, "abc")); // false
System.out.println(StringUtils.equalsIgnoreCase("abc", null)); // false
System.out.println(StringUtils.equalsIgnoreCase("abc", "abc")); // true
System.out.println(StringUtils.equalsIgnoreCase("abc", "ABC")); // true
}

public static void main(String[] args) {
System.out.println("Demo StringUtils.isBlank ---");
demoBlank();

System.out.println("\n\nDemo StringUtils.isEmpty ---");
demoEmpty();

System.out.println("\n\nDemo StringUtils.equals ---");
demoEquals();

System.out.println("\n\nDemo StringUtils.equalsIgnoreCase ---");
demoEqualsIgnoreCase();

}
}


還有太多好用的 method 了, 如: trim, substring, replace, isNumeric ... 等, 要記得去看 api ^_^.
結論 :
使用 StringUtils 可以減少錯誤的發生, 也可以少寫一些 code @@, 當然, 他的速度並不會比較慢唷, 如果跟自己寫來比的話, 能用就用吧 ^^, 如果你基礎有打好的話, 用一些別人寫的好來開發, 或許是個不錯的選擇.

2009年8月12日 星期三

Design Pattern - Template Pattern

Template Pattern

通常, 共用的方法, 我們可能會在父類別先實作, 不同的部份再定義成抽象, 由子類去實作

而Template Pattern只是告訴我們, 這些由子類別去實作的方法, 若也能抽象化呢?

舉個例子:
coco飲料店要做一杯飲料, 其中addWater(), putCup()是共用的
prepareRecipt()可以定成抽象, 各個飲料不同之處去實作


public abstract class CocoBeverage{

//boilWater(), pourlnCup(), 是共用的方法
public void addWater(){
//實作
}
public void putCup(){
//實作
}
public abstract void prepareRecipt();
}

public class MilkTea extends CocoBeverage{

public void prepareRecipt(){
addMilk();
}
public void addMilk(){
...
}
}

public class LemonTea extends CocoBeverage{

//略
public void addLemon(){
...
}
}


Template Pattern 說明, 可以提供一個公開方法, 定義出執行的步驟, 而怎麼實作可交由子類負責

所以, 上面的addMilk(), addLemon(), 其實很相同, 若能以 addCondiment統一命名, 來把這步驟抽象化呢?


public abstract class CocoBeverage{

public void addWater(){
...
}
public void putCup(){
...
}
final void executeBeverage(){ //final 注意, 不希望被繼承

addWater();
addCondiment();
putCup();
}

public abstract void addCondiment();
}

public class MilkTea extends CocoBeverage{

public void addCondiment(){
//實作加入milk
}
}

public class LemonTea extends CocoBeverage{

public void addCondiment(){
//實作加入lemon
}
}


所以我們只要去使用CocoBeverage 提供的 executeBeverage, 就可做飲料
提供抽象的CocoBeverage類別, 就是要減少client在使用時, 只依賴這class, 而不要與未來會實作的class有關聯(可以一直增加飲料種類)

--

補充1:
我們是不是可以在 executeBeverage(), 提供的template methed命名上, 加上Impl呢?
executeBeverageImpl()或templateExecuteBeverage()呢? 如此更可以讓別人一看就知用途


補充2:
Design Pattern 一書中, 提到一種勾子的模式, hook()

若我們在抽象CocoBeverage的template method中, 加入一個只宣告, 但不做事的空方法呢?

若有這hook()的存在, 可以讓子類別對template的步驟中, 不同點進行掛勾, 讓這些步驟有可能進行修改, 當然要不要勾, 由子類決定

同上, 做點修改

public abstract class CocoBeverage{
...略
final void executeBeverage(){

addWater();
if(hook()){ //預設一定會加調味料
addCondiment();
}
putCup();
}

public abstract void addCondiment();

public boolean hook(){ 這就是一個勾子, 子類別可以override, 以控制這template的步驟
return true;
}
}


我覺 hook()只是一種講法, 實現的情況會很多種, 所以還是要認清, pattern不是死的, 只是為了學習更好的寫法


補充3:
實作時, 要去繼承abstract的class這種方式, 彈性不夠
書上有舉例, 平時要排序時, 要去implements Comparable介面的compareTo(), 也是一種template pattern的實作
當要排序時, Collection.sort(Object o); 可以把這sort()想成template, 反正我們不用管sort()怎麼做的,
而且sort就是有固定的步驟, 且實現可由子類別控制,
只要我們把要排的object丟進去就好, Comparable介面就是讓我們控制的一個hook()

2009年8月11日 星期二

Configuration

Java 中有個好用的物件, Properties, 可以將常常會修改的資料存在這裡 (file) , 通常會以 .properties 結尾, 也可以用 xml 檔案.

每次要使用時, 必須寫一堆 code :

package hank.jakarta.common.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ConfigurationTest {

public static final Log log = LogFactory.getLog(ConfigurationTest.class);
public static final String propName = "mmmm.properties";

private String name;
private String working;

private Properties prop;

private ConfigurationTest() {
// do something
try {
initProp();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}

private static class SingletonHolder {
private static final ConfigurationTest instance = new ConfigurationTest();
}

public static ConfigurationTest getInstance() {
return SingletonHolder.instance;
}

private void initProp() throws IOException {
if (prop == null) {
prop = new Properties();
String realPath = getClass().getClassLoader().getResource(propName)
.getPath();
File f = new File(realPath);
if (!f.isFile()) {
throw new FileNotFoundException("path not found!! : " + realPath);
} else {
prop.load(new FileInputStream(f));
// load properties ......
setName(prop.getProperty("name"));
setWorking(prop.getProperty("working"));
}
}
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getWorking() {
return working;
}

public void setWorking(String working) {
this.working = working;
}

public static void main(String[] args) {
// test
ConfigurationTest config = ConfigurationTest.getInstance();
System.out.println(config.getName());
System.out.println(config.getWorking());
}
}



來看看紅色的地方, 每當使用時 (假設檔案是放在 classes 裡), 必須自己經過一些處理後, 再把變數都 setter 好, 才能使用. 這種是一般最常件的方法.

昨天在 surfing jakarta website 時, 看到一個好用的 tool - Jakarta commons-configuration
把一堆 code 都封裝了起來, 我們要用使就變得特別方便, 也可以設定他動態 reload 的方式.


package hank.jakarta.common.configuration;


import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ConfigurationTest1 {

public static final Log log = LogFactory.getLog(ConfigurationTest1.class);
public static final String propName = "mmmm.properties";

private String name;
private String working;

private PropertiesConfiguration prop;

private ConfigurationTest1() {
// do something
try {
initProp();
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
}

private static class SingletonHolder {
private static final ConfigurationTest1 instance = new ConfigurationTest1();
}

public static ConfigurationTest1 getInstance() {
return SingletonHolder.instance;
}

private void initProp() throws ConfigurationException {
if (prop == null) {
prop = new PropertiesConfiguration(propName);
}
// load properties ......
// String
setName(prop.getString("name"));
setWorking(prop.getString("working"));
// 如果是 double, 可以這樣寫, 就會幫你轉好了.
// prop.getDouble("double");

// 其它像 integer, ...都是.

// 那如何動態 reload 呢?, 其實很簡單
prop.setReloadingStrategy(new FileChangedReloadingStrategy());

// FileChangedReloadingStrategy <-- 這個是指, 當你修改了 attribute 時, 下一次去存取時, 會先去檢查最後修改日期, 來判斷他是否有修改, 如果有, 就 reaload.

}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getWorking() {
return working;
}

public void setWorking(String working) {
this.working = working;
}

public static void main(String[] args) {
ConfigurationTest1 config = ConfigurationTest1.getInstance();
System.out.println(config.getName());
System.out.println(config.getWorking());
}
}



今天先分享到這. 打球囉.

Quartz - 時間設定範例

 
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day-of-month 1-31 , - * ? / L W
Month 1-12 or JAN-DEC , - * /
Day-of-Week 1-7 or SUN-SAT , - * ? / L #
Year (Optional) empty, 1970-2099 , - * /

'?' - It is used to specify 'no specific value'. (used in Day-of-month, Day-of-Week only)
This is useful when you need to specify something in one of the two fields, but not the other.


以上是官方文件

範例:感謝小胖提供XD

1.每5秒
/5 * * * *
2.每5分
* /5 * * *



未完...

在<a href></a> 中新增屬性

以下是一般的用法 :

<a href="http://mmmmtodd.blogger.com/">學海無涯<a>


假如想要在 href 中新增一個屬性 "to", 裡面放的是超連結的位置, 可以這樣做 :

HTML


<span id="myHref">
<a href="javascript:void(0);" to="http://tw.yahoo.com/">yahoo<a>
<a href="javascript:void(0);" to="http://www.google.com.tw/">google<a>
</span>


JQuery

var myHref = $("#myHref a");
myHref.click(function() {
var to = $(this).attr("to");
alert(to);
// do something , ex: window.location.href=to
});

2009年8月10日 星期一

css style 位置對不齊

css style 位置對不齊


若有在網頁中宣告時

!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"

height與width必須符合w3的規定,加上px
div name=item id=item style=position:relative;visibility:;height:250px;width:300px



感謝董哥分享

2009年8月7日 星期五

Design Pattern - Adapter Pattern

Adapter Pattern

看了良葛格詳細的說明, 原來pattern還是有區別用途
gof模式
Creational 模式
Structural 模式
Behavioral 模式

這裡提到的Adapter Pattern 屬於 Structural 模式, 是如何設計物件之間的靜態結構的一個解決方案

Adapter Pattern 有分為 Object Adapter 與 Class Adapter
而 Class Adapter是要運用在多重繼承上的, java不行直接多重繼承, 這裡不提

Adapter Pattern 與 Decorator Pattern 類似, 都是要把一些物件封裝起來

當你想銜接二個不同的接口時, 可以考慮這模式, 例如:

原本開發時, 假設client端(這裡假設程式是提供給別人用, 不能輕易的改code),
在實作時, 要取得客戶資料時, 都是對應到ICustomer介面,
但後來想要增加經銷商處理的功能時...

public interface ICustomer{
public String sync();
public String save();
}


實作客戶取資料的動作

public class Customer implements ICustomer{

public String sync(){
//客戶資料的同步
}
public String save(){
//客戶資料儲存
}
}


假設這個類別是提供給客戶使用的

public class BusinessLogic{

ICustomer customer;
Public BusinessLogic(ICustomer customer){
this.customer = customer;
}

public void syncCustomer(){
customer.sync();
}
public void saveCustomer(){
customer.save();
}
}


客戶實際操作商業邏輯時

public class DemoClients{
public static void main(String[] args){
//logic
Customer c = new Customer(); //要處理customer資料時
BusinessLogic bl = new BusinessLogic(c);
bl.syncCustomer();
bl.saveCustomer();
}
}


但現在突然想加入經銷商的一些處理時, 但要處理的動作與ICustomer不同時,
可以寫個Adapter來中介


public interface IDealer{
public String buildXML();
public String save();
}

public class Dealer implements IDealer{
public String buildXML(){
//經銷商的實作xml
}
public String save(){
//經銷商的實作save
}
}


這裡是implemnts 原本的ICustomer介面, 所以對提供給user的BusinessLogic介面是相同的

public class DealerAdapter implements ICustomer{

private Dealer dealer;

public dealerAdapter(IDealer dealer){
this.dealer = dealer;
}

public String sync(){
dealer.sync();
}
public String save(){
dealer.save();
}
}


所以現在提供給user的BusinessLogic class不用動, 就可以加點東西

public class DemoNewClients{

public static void main(String[] args){

//logic
Customer c = new Customer(); //要處理customer資料時
BusinessLogic bl = new BusinessLogic(c);
bl.syncCustomer();
bl.saveCustomer();

//logic
Dealer dealer = new Dealer(); //當要處理dealer的資料時
DealerAdapter dealerAdapter = new DealerAdapter(dealer);
BusinessLogic bl = new BusinessLogic(dealerAdapter);
bl.syncCustomer(); //對user來講, 使用的接口是相同的, 但行為變了
bl.saveCustomer();
}
}

2009年8月6日 星期四

lucene2.4 - Query

1.WildcardQuery支援萬用字元 * , ?

WildcardQuery wq1 = new WildcardQuery(new Term("id", "*hank*"));
WildcardQuery wq2 = new WildcardQuery(new Term("id", "*todd*"));
bq = new BooleanQuery();
bq.add(wq1, Occur.SHOULD);
bq.add(wq2, Occur.SHOULD);
query = bq;


但使用萬用字元,會丟TooManyClauses的exception

org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024


/** Set the maximum number of clauses permitted per BooleanQuery.
* Default value is 1024.
*

TermQuery clauses are generated from for example prefix queries and
* fuzzy queries. Each TermQuery needs some buffer space during search,
* so this parameter indirectly controls the maximum buffer requirements for
* query search.
*

When this parameter becomes a bottleneck for a Query one can use a
* Filter. For example instead of a {@link RangeQuery} one can use a
* {@link RangeFilter}.
*

Normally the buffers are allocated by the JVM. When using for example
* {@link org.apache.lucene.store.MMapDirectory} the buffering is left to
* the operating system.
*/

2009年8月5日 星期三

Design Pattern - Command Pattern

Command Pattern

可將請求的動作與執行的動作分開

若假設現在的需求是要提供api給user使用時, 當然api會一直增加時

假設我們, 把使用者基本資料 封裝成 member object
api object用來封裝請求的資料, user不用管如何取得資料, 只要call execute()

整個Command Pattern可以想成有下列幾個角色
Client class --> createCommandObject() //要用的人就new object
Command class --> setCommand() //設定要使用那個命令
Invoker class --> execute() --> Command class //調用者會就去執行execute
Command class --> Receiver class //執行動作


宣告一個要執行命令的接口

public interface ICommand{
public String execute();
//public String executeXML(); //也可吐xml回去
}


實現取得客戶資料的命令 --> 注意這裡是指命令, 這裡就是把某個請求封裝起來

public class CustomerCommand implements ICommand{

Customer customer;

public CustomerCommand(Customer customer){
this.customer = customer;
}

public String execute(){
customer.getDB();
String result = customer.setXML();
return result;
}
}
public class EmployeeCommand implements Icommand(){ ... }

//實作如何取得資料, 並轉成xml
public class Customer{
getDB();
setXML();
...
}
public class Employee{ ... }


上面的 CustomerCommand class 與 Customer class就是把請求與執行分開來了

再來做一個統一對外執行的介面, 以後若有增加新的api, 這class是不需修改的,
這class 是上面提到的invoker角色(調用者)


public class APIControl(){

Command command;

public APIControl(){}

public void setCommand(Command command){
this.command = command;
}

public String doExecute(){
return command.execute();
}
}

public class DemoCallAPIP{

public static void main(String[] args){
APIControl api = new APIControl();
Customer customer = new Customer();
CustomerCommand customerCommand = new customer(customer);

api.setCommand(customerCommand); //傳入要執行的命令
String xmlResult = api.doExecute(); //就執行囉
}
}

2009年8月4日 星期二

正規表示式-regex-取出中文字

如果想要找出中文字, 可以使用 regex 對中文unicode的支援.


public static void main(String[] args) {
String oriStr = "我是小胖123444#$%^*(";
String afterStr = getChinese(oriStr);
System.out.println(afterStr); // 顯示 "我是小胖"
}
public static String getChinese(String in) {
if (in == null || ("".equals(in))) {
return "";
}
Matcher matcher = Pattern.compile("\\p{InCJKUnifiedIdeographs}").matcher(in);
StringBuffer out = new StringBuffer();
while (matcher.find()) {
out.append(matcher.group());
}
return out.toString();
}


這邊要解釋「\\p{InCJKUnifiedIdeographs}」:
在 Unicode 中,有針對各個編碼區塊做分類,它的列表可以參照下面的檔名:

Unicode 3.2 的列表:
http://www.unicode.org/Public/3.2-Update/Blocks-3.2.0.txt

Unicode 4.1.0 的列表:
http://www.unicode.org/Public/4.1.0/ucd/Blocks.txt

Unicode 5.0 的列表
http://www.unicode.org/Public/5.0.0/ucd/Blocks.txt

這個表裡面列出了統一碼區塊名和相對應的 Unicode 區段,
而其中的「CJK Unified Ideographs」就是我們的中文字區段(看名稱,應該包含日文、簡體、韓文),
而在 RegEx 中,可以透過「\p」來指定這個統一碼區塊名,
透過指定它,找出相對應的文字範圍,Java 就是這樣做的。

相關文章 : http://developers.sun.com/dev/gadc/unicode/perl/perl561.html

2009年7月31日 星期五

Design Pattern – Factory Pattern (二)

Factory Pattern

現在假設我的飲料店有很多家了, 但台北與高雄不同的店, 需要的原料會不同

所以若有個原料產生的工廠呢?

public interface SourceFactory{

public Sugar createSugar();

public Ice createIce();

}

public class TaipeiSourceFactory implements SourceFactory{

public Sugar createSugar(){

return new Sugar();

}

public Ice createIce(){

return new Ice();

}

}

public class KaoshungSourceFactory implements SourceFactory{

//自訂高雄的工廠要怎麼生產原料 xxx

}

public abstract class Beverage{

Sugar sugar;

Ice ice;

abstract void prepare();

public void box(){

//把飲料裝箱

}

}

public class MikeTeaBeverage extends Beverage{ //做奶茶

TaipeiSourceFactory taipeiSourceFactory ;

public MikeTeaBeverage(TaipeiSourceFactory taipeiSourceFactory ){

this.taipeiSourceFactory = taipeiSourceFactory ;

}

void prepare(){

Sugar sugar = taipeiSourceFactory.createSugar();

Ice ice = taipeiSourceFactory.createIce();

}

}

public class BlackTeaBeverage extends Beverage{

//相同 xxx

}

我覺上面的寫法, 跟使用utils的想法類似, 把會重複利用的拉出來

最後, 上一篇的BeverageShop, 我們來extends它, 就可以很容易的擴充了

public class CocoBeverageShop extends BeverageShop{

public Beverage createBeverage(String type){

Beverage beverage;

SourceFactory factory = new TaipeiSourceFactory(); //我coco的店要用台北的原料

if(type.equals(「紅茶")){

...

}else if(type.equals(「奶茶")){

beverage = new MikeTeaBeverage(factory);

}

return beverage;

}

}

要依賴抽象, 不要依賴實作的類 --> 不是我講的

會變動的東西, 就把它變成抽象,再去實作, 這樣物件之間的關係就可以分開

2009年7月29日 星期三

Design Pattern - Factory Pattern (一)

SimpleFactory

假設有個飲料店
public class BeverageShop{

Beverage beverage;

public Beverage orderBeverage(String type){

if(type.equals("紅茶")){
beverage = new BlackTea();
}else if(type.equals("奶茶")){
beverage = new MilkTea();
}

beverage.prepare();
beverage.box();
return beverage;
}
}


缺點:
1.未來要增加飲料種類, 要修改這class
2.prepare(),box()等等, 是固定不變的

Factory Pattern 的概念是怎麼把new一個object的處理封裝起來

現在把會變動的地方拉出來

public class SimpleBeverageFactry{

public static Beverage createBeverage(String type){

if(type.equals("紅茶")){
beverage = new BlackTea();
}else if(type.equals("奶茶")){
beverage = new MilkTea();
}
return beverage;
}
}

public class BeverageShop{

SimpleBeverageFactry factory;

//這裡把使用的factory寫死了, 不好
public BeverageShop(SimpleBeverageFactry factory){
this.factory = factory;
}

public Beverage orderBeverage(String type){

Beverage beverage = factory.createBeverage(type);

beverage.prepare();
beverage.box();
return beverage;
}
}
優點:
1.把做飲料的步驟獨立出來, 未來只要有需要飲料的地方, 都可由這產生

上面是用一個factory來new object, 我們再來試試, 用extends

public atstract class BeverageShop{

public Beverage orderBeverage(String type){

Beverage beverage = createBeverage(type);

beverage.prepare();
beverage.box();
return beverage;
}

//現在new obejct的方式, 就由extends的類別自已實作
public abstract Beverage createBeverage(String type);
}

public class CocoBeverage extends Beverage{
public Beverage createBeverage(String type){
//做出coco獨特的飲料
}
}
public class QKBeverage extends Beverage{
public Beverage createBeverage(String type){
//做出qk caffee獨特的飲料
}
}

public class demo{
public static void main(String[] args){
BeverageShop coco = new CocoBeverage();
Beverage beverage = coco.orderBeverage();

xxx
}
}

寫到這裡, 我覺factory不可能這麼單純, 上面的例子應該很好懂, 跟一般在實作時的寫法類似

2009年7月28日 星期二

Design Pattern - Decorator

Decorator Pattern 裝飾者模式

假設現在的例子是一間咖啡店, 可以產生各種飲料並計算價錢

老樣子, 先用繼承看看長怎樣 把共用的調味料寫在Beverage中, 例如milk,ice等

 
public class

Beverage{
public String description;
public int milk;
public int ice;

public getDescription();
public int calcCost(){
//計算調味料的價錢
}

//field get/set
}

public class Espresso() extends Beverage{

public int calcCost(){
//計算espresso的價錢
}
}

public class Decaf() extends Beverage{ }


Decorator Pattern 就想成是用一層層包起來的方式,

是利用組合的方式 例如 你點了一杯黑咖啡, 但你想加milk,whip ,

最後, 要計算價格 所以, 黑咖啡 <--裝飾 milk <--裝飾 whip

一些觀念:

1.裝飾者與被裝飾者要extends相同class(這裡所謂的接口是用繼承)

2.可以用一到多個去裝飾一個object

3.



public abstract class Beverage {

String description = "none";
public String getDescription(){
return description;
}

public abstract int calcCost();
}

public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}

public class Espresso extends Beverage{

public Espresso() {
System.out.println("new Espresso");
description = "buy Espresso"; //記在Beverage class
}

@Override
public int calcCost() {
System.out.println("calcCost by Espresso");
return 10;
}
}

public class Mocha extends CondimentDecorator {

Beverage beverage;
public Mocha(Beverage beverage) {
//就是這裡, 讓Mocha(裝飾者)能引用Beverage(被裝飾者)
this.beverage = beverage;
}

@Override
public String getDescription() {
System.out.println("new Mocha");
return beverage.getDescription() + ", Mocha";
}

@Override
public int calcCost() {
System.out.println("calcCost by Mocha");
return 1 + beverage.calcCost();
}
}

public class Whip extends CondimentDecorator {

Beverage beverage;
public Whip(Beverage beverage) {
//就是這裡, 讓Whip(裝飾者)能引用Beverage(被裝飾者)
this.beverage = beverage;
}

@Override
public String getDescription() {
System.out.println("new Whip");
return beverage.getDescription() + ", Whip";
}

@Override
public int calcCost() {
//自己的處理, 再加上呼叫引用的object
System.out.println("calcCost by Whip");
return 2 + beverage.calcCost();
}
}



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

Beverage beverage = new Espresso();
beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.calcCost());

Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2); //點二份Mocha, 用new Mocha去裝飾Beverage,
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);

System.out.println(beverage2.getDescription() + " $" + beverage2.calcCost());


/*
* 這裡印出來是
*
* calcCost by Whip
* calcCost by Mocha
* calcCost by Mocha
* calcCost by Espresso
* buy Espresso, Mocha, Mocha, Whip $14
*
* 這裡new了四個object, beverage2只有一份
* 分別引用了 new Espresso() <-- new Mocha() <-- new Mocha() <-- new Whip()
* 所以最後呼叫calcCost()時, calcCost()又遞迴的呼叫 beverage.calcCost();
*
*/
}
}

2009年7月27日 星期一

正則表示式-regex-範例

正則表示式 -- 範例

1.找出一段範圍
(ReDirectStart/\\*(.|[^\\*]*(\\*[^/][^\\*]*)*)\\*/ReDirectEnd+)
(xxxPos(.|[^yyyPos]*)yyyPos+)


\\d 一位阿拉伯數字
\\\\ 在java中, 單純的反斜線
() 括號讓多個表示式成為同個群組
-? 表示一個數字可接在也可不接在負號之後
-?\\d 可能有負號, 接著一或多個數字
(-|\\+)? 負號或正號, 接著一或多個數字 (因為 + 號有其他意義, 所以要加破折號)
n\\W+ 字母n後面接著一或多個非單字字元
(?m)(\\S+)\\s+((\\S+)\\s+(\\S+))$ 找出每行最後三個字

HttpClient 3_configuration

想多了解的人, 當然, 自己多看看 Java Doc 囉.
以下列出幾個常用的.

1. Add Headers

GetMethod method = new GetMethod();
method.addRequestHeader("headerName", "headerValue");
// or
method.addRequestHeader(new Header("headerName", "headerValue"));


2. 設定 timeout 時間

HttpMethodParams params = new HttpMethodParams();
params.setSoTimeout(3000);

// or
method.getParams().setSoTimeout(3000);


3. 多執行序下使用 HttpClient

HttpClient client = new HttpClient(new MultiThreadedHttpConnectionManager());
// or
MultiThreadedHttpConnectionManager config = new MultiThreadedHttpConnectionManager());
// set other config
HttpClient client = new HttpClient();
client.setHttpConnectionManager(config);

補充: 如果您的程式會一直使用 httpclient 發送 request, 建意將 httpclient 宣告成只有一份(ex: static or singleton), 減少不必要要的 port 被開啟, 又要等待 system close.

4. 失敗時, retry 3 次

// set per default
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler());
// or
DefaultMethodRetryHandler retryhandler = new DefaultMethodRetryHandler(10, true);
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryhandler);

// 如果想了解哪些情況下, 才會 retry, 請參考官網 http://hc.apache.org/httpclient-3.x/tutorial.html



目前這些囉, 有想到什麼常用的到時候再補充唷.

HttpClient 2_post method

b) port method : 看完 get method 後, 其實 post method 大同小異, 差別在於物件不同而已.

public PostDemo {

public static void main (String[] args) throws Exception {
HttpClient client = new HttpClient();
PostMethod method = new PostMethod("http://www.google.com.tw");
int httpcode = client.executeMethod(method); // 執行
if (httpcode == HttpStatus.SC_OK) {
System.out.println("連線成功");
} else {
System.out.println("連線失敗");
}

// 用完記得關閉
method.releaseConnection();
}
}


取得結果 :

...
if (httpcode == HttpStatus.SC_OK) {
System.out.println("連線成功");
// 取得結果有幾種方法,
// 1. method.getResponseBodyAsString() , 測試用的話沒關係, 但量大會造成效能不佳, 也不建議使用
// 2. method.getResponseBodyAsStream()
InputStream in = method.getResponseBodyAsStream();

// 自己轉換成 String
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String temp = null;
while ((temp = reader.readLine()) != null) {
result.append(temp);
}
// 這樣就能將做後續的處理囉...
}
...


其它參數

PostMethod method = new PostMethod(yourUrl);
// add parameters
method.addParameter("parameterName", "parameterValue");
// ... 如果有一個以上

// post image file
Part[] parts = { new StringPart("param1", "我是小胖"),
new StringPart("param2", "體重65"),
new StringPart("param3", "這 2 天變曬黑了"),
new FilePart("personalPic", new File("D:\\小胖照片.jpg")) };

method.setRequestEntity(new MultipartRequestEntity(parts, method
.getParams()));


Post & Get 這 2 個方法應該可以滿足很多需求, 下一篇將介紹其它的 config 如何設定, 如 add header, set timeout, retry handler, multi thread ...等.

2009年7月25日 星期六

Design Pattern - Observer

Observer 觀察者模式

假設有個需求

提供一個佈告欄, 分別提供 blog與forum頻道的資訊
1.希望會自動更新所有佈告欄
2.要容易增加新的佈告欄

或許我們可以這樣寫


//當資料有更新時
public class BulletinData{

public void update(){

String title = getTitle(); --> 也許直接去db撈, 或者call api
String content = getContent();

BulletinBlog.update(title, content);
BulletinForum.update(title, content);

}
}

public class BulletinBlog{
public void update();
public void display();
}

public class BulletinForum{
public void update();
}


觀察者模式就是 主題與觀察者一對多的關係
以出版社為例
出版者 + 訂閱者 = Observer模式

subject <-- 1 對多 --> observer

或許可以這樣寫

public interface ISubject{
public void registerObserver(IObserver o);
public void removeObserver(IObserver o);
public void notifyObserver();
}

public interface IObserver{
//這裡把這些field值寫死了, 不好
public void update(String title, String content);
}

public interface IDisplay{
public void display();
}

//資料來源的BulletinData當作subject
public class BulletinData implements ISubject{

private List lobserver;
private String title;
private String content;

public BulletinData(){
lobserver = new ArrayList();
}

public void registerObserver(IObserver o){
lobserver.add(o);
}

public void removeObserver(IObserver o){
lobserver.remove(o);
}

public void notifyObserver(){
for (int i = 0; i < lobserver.size(); i++) {
Observer observer = (Observer)lobserver.get(i);
observer.update(this.title, this.content);
}
}

public void update(){
notifyObserver();
}

public void setNewData(String title, String content){
this.title = title;
this.content = content;
this.update();
}
}

public class BulletinBlog implements IObserver, IDisplay{
private String title;
private String content;
private ISubject bulletinData;

public BulletinBlog(ISubject BulletinData){
this.bulletinData = bulletinData;
BulletinData.registerObserver(this); --> 註冊成為觀察者
}

public void update(String title, String content){
this.title = title;
this.content = content;
display();
}

public void display(){}
}

public class BulletinForum implements IObserver, IDisplay{
...
}

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

BulletinData bulletinData = new BulletinData();

BulletinBlog bulletinBlog = new BulletinBlog(bulletinData);
BulletinForum bulletinForum= new BulletinForum(bulletinData);

//當資料有更新時, 也許直接去db撈, 或者call api
String title = "new title";
String content = "new content";
bulletinData.update(title, content); --> 會通知所有有註冊的觀察者了
}
}


subject依賴的是一個observer的interface, 所以subject不用管有多少class去implements
以上的作法,

java.util 有提供Observer模式
java.util.Observer 這是interface, 讓我們implents觀察者
java.util.Observable 可以去extends Observable class, 再去增加取得新資料的方法

上方的例子, 主動權是在subject, 都是由subject去把資料推給觀察者,
而java.util提供的Observer可以做到由觀察者自己去拉資料

下方的code是由java.util提供方式來實作
head first design pattern一書copy貼上的, 請參考用



import java.util.Observable;
import java.util.Observer;

public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;

public WeatherData() { }

public void measurementsChanged() {
setChanged();
notifyObservers();
}

public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}

public float getTemperature() {
return temperature;
}

public float getHumidity() {
return humidity;
}

public float getPressure() {
return pressure;
}
}

import java.util.Observable;
import java.util.Observer;

public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}

public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}

public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}




名言??
松耦合 --> 當二個object可以交互, 但又不清楚彼此的細節

2009年7月24日 星期五

HttpClient 1_get method

1. 分享一下最近使用 HttpClient 的心得.
2. HttpClient 可以做很多事情, 這裡不多說, 有興趣的人可以先上官網了解一下.
3. 目前 version 4 尚未正式發怖, 這裡還是使用 3.x 版來做介紹.

request ( get & post)
a) get method : 先看程式如何實作出一個 get 連線:

public GetDemo {

public static void main (String[] args) throws Exception {
HttpClient client = new HttpClient();
GetMethod method = new GetMethod("http://www.google.com.tw");
int httpcode = client.executeMethod(method); // 執行
if (httpcode == HttpStatus.SC_OK) {
System.out.println("連線成功");
} else {
System.out.println("連線失敗");
}

// 用完記得關閉
method.releaseConnection();
}
}


發出去囉...但...我想把結果撈回來看...怎麼寫呢?....其實很簡單...我們在 httpcode == 200 下面加上一段 code :

...
if (httpcode == HttpStatus.SC_OK) {
System.out.println("連線成功");
// 取得結果有幾種方法,
// 1. method.getResponseBodyAsString() , 測試用的話沒關係, 但量大會造成效能不佳, 也不建議使用
// 2. method.getResponseBodyAsStream()
InputStream in = method.getResponseBodyAsStream();

// 自己轉換成 String
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String temp = null;
while ((temp = reader.readLine()) != null) {
result.append(temp);
}
// 這樣就能將做後續的處理囉...
}
...

JQuery 與 Prototype 的衝突.

這裡提供2種常用的解決方法

1: 使用 jQuery.noConflict():

jQuery.noConflict();
// 將 JQuery 的 $ 用 jQuery 代替
jQuery(document).ready(function(){
// doSomething
});



2: 給一個簡短的名字:

var $J = jQuery.noConflict();
// 將JQuery的 $ 用 $J 代替
$J(document).ready(function(){
// doSomething
});

2009年7月23日 星期四

Design Pattern - 什麼是鴨子模式?

什麼是鴨子模式?

之前開發時最常用extends的方式, 通常把共用的東西寫在一起

缺點:
1.父類很難預知到extends的所有共用的東西 (未來沒事別改主要的code)
2.若要改共用的東西, 要檢查所有extends
3.???


Bird class
display()
fly()

Hooter class
fly()

Sparrow class
fly()


new hooter().fly(); --> 這時每一種鳥怎麼飛就寫死

因為每種鳥的飛行方式不太一樣, 所以若把各種飛的方式分別實作, fly()改成interface


public interface FlyBehavior
fly()

public class FlyFast implements FlyBehavior
fly(){ 飛很快 }

public class FlySlow implements FlyBehavior
fly(){ 飛很慢 }


public abstract class Bird{
public FlyBehavior flyBehavior;

public abstract void display(){}

public doFly(){
flyBehavior.fly(); --> delegate
}

public void setFlyBehavior(FlyBehavior fb){
this.flyBehavior = fb;
}
}

public class Hooter extends Bird{

public Hooter(){
flyBehavior = new FlyFast();
xxx = new xxx();
}
}

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

//直接寫在建構子裡, 這樣在new Hooter()時, 就決定它的fly方式, 但這樣寫不太好
Bird hooter = new Hooter();
hooter.doFly();

//不過我們的Bird class有setFlyBehavior,
//這裡就可以動態的使用那一個實現fly的class了
Bird hooter2 = new Hooter();
hooter2.setFlyBehavior(new FlySlow());
hooter2.doFly();
}
}


書上講的名言?
1.可能會變的地方,就獨立封裝起來,不要跟固定的code寫在一起
2.針對接口編程,而不是針對實現編程
不太懂, 可能是指要實現一個功能, 不要直接就寫class了, 反正隨時用interface就對了吧

以上是參考head first design pattern一書的理解

2009年7月22日 星期三

Design Pattern - Singleton

良葛格已分享許多方法與範例, 在此提供 Inner Class 的方法


public class SingletonDemo {

private SingletonDemo() {
// do something...
}

public static SingletonDemo getInstance() {
return SingletonHolder.instance;
}

private static class SingletonHolder {
private static final SingletonDemo instance = new SingletonDemo();
}

public void function1()....
public void function2()....
}