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()....
}