<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6300120481261832269</id><updated>2012-02-16T16:40:19.258-08:00</updated><category term='淺談設計模式'/><category term='美學運算'/><category term='日常生活'/><category term='Java'/><category term='物件導向技術之詮釋學'/><category term='Javascript'/><category term='瞎掰'/><title type='text'>言式法則</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-3303322505754751072</id><published>2010-11-30T03:34:00.000-08:00</published><updated>2011-09-02T04:24:14.234-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='日常生活'/><title type='text'>當兵前驗出僵直性脊椎炎</title><content type='html'>Q：役男在當兵前驗出僵直性脊椎炎應該如何處理？&lt;br&gt;A：請申請兵役複檢。&lt;br&gt;&lt;br&gt;在7月底繳了畢業證書影本到鄉公所，希望公所兵役課人員幫我排9月的梯次，豈料適逢碩博士畢業潮，9月、10月的梯次大部分名額都讓年次比較前面的畢業生佔走了，不斷詢問之下終於在10月初確定入伍時間為11月3日。然而，正當我問著「在不強迫健康女人懷孕生子的年代，為什麼一個半殘男人竟有服兵役的義務？」這個問題時，&lt;a href="http://dept.cmuh.org.tw/layout_1/?id=D16583&amp;amp;type=detail&amp;amp;%2Flayout_1%2Findex.php%3FPage%3D%26orderby_field%3D%26orderby_kind%3D%26search_field%3D%26search_keyword%3D&amp;amp;PmeDept=&amp;amp;did=20106"&gt;中國醫藥大學附設醫院中醫傷科的劉醫師&lt;/a&gt;就像下凡來傳福音的天使一樣，為我帶來了一絲曙光－「你可能有僵直性脊椎炎」祂如是說。是的，不是我刻意逃兵，而是六年前就開始時好時壞的腳痛最近又惡化，連走路都一拐一拐，根本不可能跑步，去當兵難道是貪圖一群男人的服侍？我可沒有這種性向，不過已經收到兵單了。在劉醫師的建議下，我到署立彰化醫院掛了免疫風濕科，&lt;a href="http://www.chhw.doh.gov.tw/?aid=51&amp;amp;pid=101&amp;amp;page_name=detail&amp;amp;iid=48"&gt;免疫風濕科高醫師&lt;/a&gt;看了我之前在復健科檢查時拍的腰部X光後就說「你這個有問題耶」，當下就確定是僵直性脊椎炎，還開了診斷書。由於沒聽說過家人有僵直性脊椎炎的病史，高醫師建議我抽血檢查看是不是有這樣的抗原，所以那天抽完血才回家。&lt;span class="Apple-style-span" style="color: #666666;"&gt;(相當感謝這兩位細心的醫師，在此之前我看過10個以上的醫師，包括骨科、復健科、神經內科，其中也不乏有名的台大與台北馬偕，都沒診斷出來，甚至一副質疑我想逃兵的樣子。)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;目前僵直性脊椎炎的免役標準為&lt;/span&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;※&lt;/span&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;：&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-style-span" style="color: red;"&gt; 1. 血清檢察HLA-B27陽性，併發薦腸關節炎。※&lt;/span&gt;&lt;br&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span style="color: red;"&gt;2. 血清檢察HLA-B27陰性，薦腸關節之發炎單側第三級以上或雙側第二級以上。&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span style="color: red;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/div&gt;&lt;a href="http://yensrule.blogspot.com/2010/11/blog-post.html#more"&gt;閱讀更多 »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-3303322505754751072?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/3303322505754751072/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/11/blog-post.html#comment-form' title='40 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/3303322505754751072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/3303322505754751072'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/11/blog-post.html' title='當兵前驗出僵直性脊椎炎'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-8491830830902982642</id><published>2010-10-12T00:27:00.000-07:00</published><updated>2011-05-15T03:27:45.721-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>Overloading VS. Overriding</title><content type='html'>剛學物件導向程式設計的人常常把Overriding與Overloading兩個詞搞混，不僅是因為這兩個單字看起來很像，連使用方式都很類似。於是愛用國貨的中文書市場為了造福國內廣大英文辨識力不良族群，推出了以下絕妙的通俗翻譯：&lt;br&gt;&lt;ul&gt;&lt;li&gt;Overloading＝多載。&lt;/li&gt;&lt;li&gt;Overriding＝覆載。&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;這翻譯絕妙的地方在於繼承了英文單字看起來很類似的特性，從字面來看也很難明白其中意涵，於是還是讓人看得霧煞煞，令人不禁想豎起大拇指大讚「這就是物件導向啊！」&lt;br&gt;就在這個時候，國內的大學生發現這可能是教授為了能當更多人而玩的文字遊戲，又或者是當初的翻譯者害怕太多人學會之後飯碗不保，刻意翻得很奇怪，於是提出更明確的翻譯方式以自救：&lt;br&gt;&lt;ul&gt;&lt;li&gt;Overloading ＝ 給予太多工作 (load多到太over)。&lt;/li&gt;&lt;li&gt;Overriding ＝忤逆家長 (也就是ride在家長頭上太over的意思)。&lt;/li&gt;&lt;/ul&gt;&lt;a href="http://yensrule.blogspot.com/2010/10/overloading-vs-overriding.html#more"&gt;閱讀更多 »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-8491830830902982642?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/8491830830902982642/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/10/overloading-vs-overriding.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/8491830830902982642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/8491830830902982642'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/10/overloading-vs-overriding.html' title='Overloading VS. Overriding'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-1180541430802188726</id><published>2010-06-02T09:16:00.000-07:00</published><updated>2011-05-15T03:28:40.258-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='瞎掰'/><title type='text'>最難得的是有水準的觀眾</title><content type='html'>如果有人問我哪一場音樂表演是令我印象最深刻的，我的回答大概是那場辦在台中洲際棒球場的張藝謀執導的《杜蘭朵公主》，因為那天的觀眾實在不是烏合之眾足以形容的。以觀眾數量看來票賣得不錯，但似乎就是很少人注意到節目開始前就不斷宣導的「表演期間請勿拍照」，也似乎很少人真正想去欣賞這場歌劇，全場一團團閃光燈的閃爍以及一陣陣觀眾的討論聲，引人注目的程度甚至快壓過台上的表演與樂聲。不關手機的人很多，表演中手機拿起來直接放聲高談自己多麼無法接受歌劇的也是大有人在。我正前方與右方的觀眾忙著拍照，我正後方的觀眾則在聊著與演出不太相關的事情，在這種三面受敵的情況下，要人如何能去享受一齣歌劇？在演出結束，演員出來謝幕之前，一群人開始離場，彷彿從一開始就期待這一刻的到來，留著為優秀的導演、演唱家及指揮鼓掌喝采的，大約只有三分之二。相信我，那場演出的水準絕對沒有差到這種程度，甚至男高音、指揮家以及兒童合唱團的水準都是相當罕見的，沒有理由令觀眾反感到這種程度。後來我在離開時聽見幾個觀眾說：「要欣賞歌劇這種東西，真的是要有興趣。」原來他們並不是因為對歌劇有興趣才來欣賞這場演出。我相信這麼多觀眾對這場演出不滿意，主要是因為演出與他們的期望不一致。也許他們真正想要看的是音樂劇，而在他們人生中還沒有人告訴他們音樂劇與歌劇是不一樣的東西。另外一個原因也許是這場演出的贊助商太多，這些贊助商都拿了很多貴賓券，而最後拿到這些貴賓券的人究竟對節目感不感興趣就看運氣。當我在上層的位置看到貴賓券的區域呈現出類似銀河的景象，我想他們大多數應該都只是來湊熱鬧的。於是演出的水準與觀眾的能耐呈現強烈的對比，對表演藝術而言，沒什麼能比這更糟的了。&lt;br&gt;&lt;a href="http://yensrule.blogspot.com/2010/06/blog-post.html#more"&gt;閱讀更多 »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-1180541430802188726?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/1180541430802188726/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/06/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1180541430802188726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1180541430802188726'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/06/blog-post.html' title='最難得的是有水準的觀眾'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-463046913764555518</id><published>2010-03-05T10:57:00.000-08:00</published><updated>2011-05-15T03:29:00.977-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='瞎掰'/><title type='text'>創作與惡搞的差別</title><content type='html'>對我而言，惡搞只是一種創作方式，因此對於弄清楚創作與惡搞的差別，一時間我還真不知該說什麼才好，於是乎我求助了&lt;a href="http://zh.wikipedia.org/zh-tw/%E6%83%A1%E6%90%9E%E6%96%87%E5%8C%96"&gt;維基百科&lt;/a&gt;。它給了我以下解釋：&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="color: #999999; font-style: italic;"&gt;惡搞文化，指的是對嚴肅主題加以解構，從而建構出喜劇或諷刺效果的胡鬧娛樂文化。常見形式是將一些既成話題，節目等改編後再次發布，屬於二次創作的其中一手法。惡搞在當代流行文化中很常見。&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;這串字裡最吸引我的兩個字是「解構」，看到這兩個字，我才終於了解為什麼我搞不清楚差別在哪裡。&lt;br&gt;&lt;br&gt;&lt;a href="http://yensrule.blogspot.com/2010/03/blog-post.html#more"&gt;閱讀更多 »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-463046913764555518?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/463046913764555518/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/03/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/463046913764555518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/463046913764555518'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/03/blog-post.html' title='創作與惡搞的差別'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-4940726863828270508</id><published>2010-01-30T09:28:00.000-08:00</published><updated>2010-01-30T10:24:26.133-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='瞎掰'/><title type='text'>用Java盡大學生的義務</title><content type='html'>最近總是出現一堆新聞在報導時下大學生的醜態，舉凡遲到、翹課、上課吃雞腿、考試作弊等等。每次看到這類新聞，都不禁為這些大學同學感到惋惜。但是，請不要誤會，我寫這篇文章的目的絕不是要炫耀自己是個努力用功人見人愛的乖學生，而是這些醜態我在大學前就全都幹過了。我惋惜的不是他們和我一樣糟，而是可憐他們運氣差，剛好符合媒體的胃口而被爆料。&lt;br /&gt;身為一個大學生，我大約知道公認的義務，這些義務不外乎：&lt;ol&gt;&lt;li&gt;記得上課&lt;/li&gt;&lt;li&gt;但是不要遲到&lt;/li&gt;&lt;li&gt;過程中保持清醒&lt;/li&gt;&lt;li&gt;再餓也不能吃雞腿&lt;/li&gt;&lt;li&gt;沒雞腿吃也要認真聽課&lt;/li&gt;&lt;li&gt;快被二一，仍保持考試不作弊&lt;/li&gt;&lt;li&gt;就算作業完全不會寫，也不能抄襲，而且要準時交&lt;/li&gt;&lt;/ol&gt;大學生簡直是聖人了！&lt;br /&gt;&lt;br /&gt;對我這個糟糕大學生而言，只有兩件事情是必須做的：&lt;ol&gt;&lt;li&gt;註冊&lt;/li&gt;&lt;li&gt;選課&lt;/li&gt;&lt;/ol&gt;這麼說或許漠視了全天下負責繳學費的父母與全天下努力教書的老師們的期望。確實，每個父母都希望孩子成龍成鳳；每個教授都希望學生認真聽課；每個公民都希望學生(尤其是那些念到台大醫科的)不要浪費社會資源。然而，我認為大學不僅是一個鑽研學術的機構，更是個學習如何抉擇的小社會：除了註冊與選課外，其他義務應是學生了解做的理由後才選擇去做的，否則，我們的教育還是在製造同樣思維的人，與我們一直要擺脫的填鴨式教育並無什麼不同。&lt;br /&gt;&lt;br /&gt;看到這裡，一定有人開始懷疑本文與主題的關係。但是，別著急，按照慣例，接下來的文章一定會努力拗回正題的！&lt;br /&gt;我真的要說的是，每次我在執行「選課」這項大學生的義務時，總是會遇到相當多競爭者要搶同一門課，而且好死不死每次運氣都很差，抽籤的結果總是沒選到，只好在加退選階段等選上的人退選。然而加退選階段搶課的人還是很多，每次為了選到一門課，都得坐在電腦前不斷按加選按鈕，浪費了相當多時間。為了剷除那些妨礙我盡大學生義務的絆腳石，上次選課時，我終於下定決心寫出一個滑鼠連點程式(然而，當程式一完成，開始讀秒準備發射時，我才發現想選的課已經選上了..囧rz)。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;本文要教大家做的就是如何以Java實作滑鼠連點程式。程式碼十分短，大約只要15行。&lt;/span&gt;&lt;br /&gt;在此先介紹Java AWT裡的一個稱為Robot的類別，大家可別看到名字就以為是給搜尋引擎用來做網路蜘蛛(Web Spider)的，事實上我有個不懂裝懂的同學就這麼想；也不要認為它是用來做機器人行動規畫的工具，它和真實的機器人一點關係也沒有。它其實是個用來模擬圖形介面使用者動作的類別。換句話說，它可以模擬使用者滑鼠移動、按下鍵盤或滑鼠按鍵，並且可以擷取目前螢幕的畫面。&lt;br /&gt;&lt;br /&gt;Robot類別提供以下幾個方法來模擬滑鼠動作：&lt;br /&gt;&lt;ul style="color: rgb(255, 0, 0);"&gt;&lt;li&gt;public void mouseMove(int x, int y); // x,y為螢幕像素位置&lt;/li&gt;&lt;br /&gt;&lt;li&gt;public void mousePress(int buttons);&lt;br /&gt;/* buttons可以是以下的值&lt;br /&gt;* java.awt.event.InputEvent.BUTTON1_MASK 代表左鍵&lt;br /&gt;* java.awt.event.InputEvent.BUTTON2_MASK 代表中鍵&lt;br /&gt;* java.awt.event.InputEvent.BUTTON3_MASK 代表右鍵*/&lt;/li&gt;&lt;br /&gt;&lt;li&gt;public void mouseRelease(int buttons);   //同上&lt;/li&gt;&lt;br /&gt;&lt;li&gt;public void mouseWheel(int wheelAmt);&lt;br /&gt;/* wheelAmt為滑鼠滾輪的轉動量，&lt;br /&gt;* 正值為向前轉，負值為向後轉。*/&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;注意按下(press)滑鼠按鍵後，必須放開(release)才是一次點擊(click)。若忘了把按鍵放開，按鍵會一直被按著。&lt;br /&gt;&lt;br /&gt;連點程式全部的程式碼只有這樣：&lt;br /&gt;&lt;pre style="font-family: times new roman; font-style: italic; color: rgb(153, 153, 153);"&gt;import java.awt.*;&lt;br /&gt;import java.awt.event.*;&lt;br /&gt;class RobotTest{&lt;br /&gt;    public static void main(String[] arg)throws AWTException,&lt;br /&gt;                                                InterruptedException{&lt;br /&gt;        Robot robot = new Robot();&lt;br /&gt;        while(true){&lt;br /&gt;              robot.mousePress(InputEvent.BUTTON1_MASK);&lt;br /&gt;              robot.mouseRelease(InputEvent.BUTTON1_MASK);&lt;br /&gt;              Thread.sleep(3000);  // 讓執行緒睡3秒&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;注意在每次點擊必須讓執行緒暫停一段時間，否則滑鼠會不停點擊，到時連這個連點程式都很難關掉。&lt;br /&gt;&lt;br /&gt;這裡只介紹到Robot類別的一種應用，事實上他能夠實現相當多功能，諸如螢幕放大鏡、螢幕畫面擷取器之類的小程式。&lt;br /&gt;有興趣深入的人可以參考Java API的介紹：&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Robot.html"&gt;Robot&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-4940726863828270508?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/4940726863828270508/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/01/java.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/4940726863828270508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/4940726863828270508'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/01/java.html' title='用Java盡大學生的義務'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-6963757722230586986</id><published>2010-01-24T20:34:00.000-08:00</published><updated>2010-01-27T07:57:54.290-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>正名運動：Java與JavaScript不是直系血親</title><content type='html'>&lt;span style="font-family:times new roman;"&gt;有相當多人認為Java與JavaScript存在著某種關係，更有人認為JavaScript其實是Java的變形體，然而若對JavaScript的歷史稍有研究，你可以發現JavaScript與Java可以說是一點關係也沒有，全都是名字與刻意模仿的命名誤導了大家。&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;JavaScript的原名為LiveScript，由&lt;/span&gt;&lt;a style="font-family: times new roman;" href="http://en.wikipedia.org/wiki/Brendan_Eich"&gt;Brendan Eich&lt;/a&gt;&lt;span style="font-family:times new roman;"&gt;所設計，1996年誕生於網景(Netscape)公司。當時的網景公司是瀏覽器的霸主，為了推行這種新穎的動態網頁技術而和昇陽(Sun Mirco Systems)公司達成協議，將LiveScript更名為JavaScript(因為昇陽的Java Applet在當時曾風光一時，藉由Java的名號推廣新技術比較容易。)，網景公司則以幫助昇陽研發Navigator瀏覽器上的虛擬機器(VM)做為交換條件，也因此JavaScript的商標權目前是屬於昇陽。換句話說，JavaScript最多只是Java的乾兒子，何況在程式語言的系譜上，Java與JavaScript的關係也不在同一條血脈上。Java在特性上承繼了C++與SmallTalk，有著封裝、繼承與多型三種傳統物件導向程式語言的主要特徵，反觀JavaScript，嚴格來說沒有封裝與繼承，更不用說多型。JavaScript雖然有成員變數與成員函式的觀念，但與其說那是封裝，不如說是沒有存取權限控制的關聯式陣列(associative array)，例如在Java中宣告一個類別：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;class JavaClass{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    private String name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    int id;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;String型態的name變數只能在其宣告的類別內存取，整數型態的id變數則可以在所屬package內存取，然而在JavaScript，當你這樣宣告：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;function JavaScriptClass(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;    this.name = "Default";&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;    this.id = 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-family:times new roman;font-size:85%;"  &gt;※JavaScript的實體建構函式(建構子)與一般函式是沒有分別的，因此當下文提到建構子，即是指程式中專門用來建構實體(new)的函式。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;name和id的存取是不用考慮權限的，甚至可以用以下兩種方式來存取實體內的成員變數：&lt;/span&gt;&lt;br /&gt;&lt;ol  style="font-family:times new roman;"&gt;&lt;li&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;var instance = new JavaScriptClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;instance["name"];   // = "Default"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;instance["id"]; // = 0&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;var instance = new JavaScriptClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;instance.name;    // = "Default"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;instance.id;    // = 0&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;換句話說，instance變數可被看成含有name與id成員變數的物件，也可以視為是一個以字串為鍵(key)的關聯式陣列，建構子的宣告只是幫助我們將陣列內的鍵與值先做初始化。&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;在JavaScript中，要製造出多個有相同成員變數與成員函式的物件，宣告一個function來作為實體的建構子會比較方便，但如果實體只會被使用一次，也可以用下列的方式來宣告：&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;pre style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;&lt;br /&gt;var instance = new Object();&lt;br /&gt;instance.name = "JavaScript";&lt;br /&gt;instance.id = 1;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;pre style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;// 或者是 var instance = new Array();&lt;br /&gt;var instance = new Object();&lt;br /&gt;instance["name"] = "JavaScript";&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;pre style="font-family:times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;&lt;br /&gt;instance = {&lt;br /&gt;    name : "JavaScript",&lt;br /&gt;    id : 3&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;習慣寫Java的人可能會覺得第一種寫法很弔詭，但在JavaScript裡確實是行得通的：即使Object的實體裡不存在name與id變數，只要有指派，變數就自動被配置了。也因此第二種寫法看起來較直覺，只要把實體全部看成關聯式陣列(或 Hash Table)就行了。第三種寫法是以JSON(JavaScript Object Notation)的方式寫成，但如果你用過&lt;/span&gt;&lt;a style="font-family: times new roman;" href="http://www.rubyist.net/%7Eslagell/ruby/arrays.html"&gt;Ruby的關聯式陣列&lt;/a&gt;&lt;span style="font-family:times new roman;"&gt;，就會覺得這種寫法用來宣告關聯式陣列是再正常不過了。&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;到這裡，很明顯可以看出Java與JavaScript的不同之處，然而他們最大的不同是在函式的特性：&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);font-family:times new roman;" &gt;JavaScript的函式本質上仍屬於關聯式陣列的值，而非任何實體的成員函式&lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;。例如，當你在一個建構函式內宣告一個成員函式：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;function JavaScriptClass(){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    this.name = "Hello";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    this.displayName = function(){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;        alert(this.name);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;var obj = new JavaScriptClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;obj.displayName();&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;雖然以上的程式會確實會彈出一個警告視窗顯示"Hello"，但如果你的程式是像這樣寫，也會有同樣的結果：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;function func(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;    alert(this.name);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;function JavaScriptClass(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;    this.name = "Hello";&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;var obj = new JavaScriptClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;obj.displayName = func;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102); font-style: italic;"&gt;obj.displayName();&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-family:times new roman;font-size:85%;"  &gt;※注意obj.displayName = func的func後面沒有大括號，懂C的人可以把它視為函式指標。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;知道原因嗎？obj實體的displayName函式並不是成員函式，因此displayName函式中的this並不是函式所屬的物件，而是函式的「呼叫者」。換句話說，obj.displayName()呼叫時，displayName函式是到呼叫者(obj)去尋找name變數。下列寫法應會比較容易理解：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;function func(){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    alert(this.name);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;function JavaScriptClass(){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    this.name = "Hello";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;var obj = new JavaScriptClass();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;func.call(obj);&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;在JavaScript中，當一個函式被呼叫，實際上是呼叫函式物件中的call函式。call函式的第一個參數為該函式物件的呼叫者，也就是說函式內的this關鍵字會關聯到call函式的第一個參數，因此當func函式執行this.name變數時，實際上是到obj實體尋找name變數。了解其中的機制後，就可以用JSON當作參數傳入函式而得到同樣的效果：&lt;/span&gt;&lt;br /&gt;&lt;pre  style="font-family:times new roman;"&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;function func(){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;    alert(this.name);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 102, 102);"&gt;func.call({name:"Hello"});&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;JavaScript就是一個原理如此簡單的語言！&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;翻開族譜，JavaScript真正的祖宗其實是Self與Scheme，才會有像prototype與第一級函式的特性。那麼，誰才是Java真正的兒子？除了源自於Java的Groovy外，最像Java的語言應是那位認錯祖宗的C#吧！&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-6963757722230586986?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/6963757722230586986/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/01/javajavascript.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6963757722230586986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6963757722230586986'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/01/javajavascript.html' title='正名運動：Java與JavaScript不是直系血親'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-6210117411945938930</id><published>2010-01-23T06:59:00.000-08:00</published><updated>2010-01-28T18:34:48.923-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='淺談設計模式'/><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>淺談設計模式之觀察者模式</title><content type='html'>&lt;span style="font-family:times new roman;"&gt;小明是個勤奮的台科大學生，平時相當努力在做一些與課業毫不相干的事情，例如在計算機網路期末考的前一晚還在研究Java的反射機制。如此的勤奮，以至於他在學期結束時發現有半數以上的老師不打算讓他過關。就這樣，小明被二一了。被二一的小明在學期結束後恐懼於父母的鞭打，隱藏自己提早畢業的事實，藉故留在台北，打算就這樣瞞天過海不理人間世事，用心鑽研Java。不料，紙終究包不住火，某日小明在宿舍享受著Java優雅的語法時，一陣急促的敲門聲打斷了他的思緒。小明不耐煩地開了門，還沒來得及看清楚來訪者的臉之前就先被一記大腳踹到牆邊，抬頭一看才驚見自己青筋暴現面目猙獰的老爸。這時，小明才終於意會到，老爸是自己在學資料的觀察者之一，同樣會被告知自己被二一的消息...&lt;br /&gt;儘管可能有人好奇小明的下場，這畢竟不是這篇文章要講述的重點，這篇文章的重點是「觀察者模式」的實作，也就是說明在物件導向程式設計中，如何實作物件與物件的註冊與通知機制，而上述的人倫悲劇即是我們要實作的情境。小明的下場如何，請看倌自行想像。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;觀察者模式包含兩種角色：「觀察者(Observer)」、「被觀察者(Observable)」。觀察者與被觀察者都能夠有多個：一個「被觀察者」能夠被許多「觀察者」觀察，一個「觀察者」也能一次觀察多個「被觀察者」。「觀察者」必須向「被觀察者」註冊，「被觀察者」在狀態改變或某些條件滿足時則告知「觀察者」&lt;/span&gt;，如下圖所示。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-family: times new roman;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_15zvGmmKTdk/S1sPDD0X0oI/AAAAAAAAFY8/OZqzcvcKpeM/s1600-h/observer+pattern.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer; width: 400px; height: 158px;" src="http://1.bp.blogspot.com/_15zvGmmKTdk/S1sPDD0X0oI/AAAAAAAAFY8/OZqzcvcKpeM/s400/observer+pattern.png" alt="" id="BLOGGER_PHOTO_ID_5429950320964260482" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;觀察者必須提供一個方法(update)讓被觀察者在狀態更新時呼叫，被觀察者也必須提供觀察者註冊(addObserver)及移除(removeObserver)的方法，如下介面所定義：&lt;br /&gt;&lt;pre style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;interface Observer{&lt;br /&gt;   /** 通知此觀察者*/&lt;br /&gt;   public void update(String message);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Observable{&lt;br /&gt;    /** 增加觀察者 */&lt;br /&gt;    public void addObserver(Observer observer);&lt;br /&gt;    /** 移除觀察者*/&lt;br /&gt;    public void removeObserver(Observer observer);&lt;br /&gt;}&lt;/pre&gt;Observable介面的addObserver方法雖暗示了實作類別必須使用陣列或串列來儲存多個觀察者實體，但這並非強制性的，一個被觀察者也能只有一個觀察者，取決於整體的設計。Observer介面中的update方法所傳遞的參數也取決於使用的場合。若要設計出較一般化的Observer模式的實作，可以參考Java API中的&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Observer.html"&gt;Observer&lt;/a&gt;介面和&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Observable.html"&gt;Observable&lt;/a&gt;類別。&lt;br /&gt;&lt;br /&gt;在實作上述情境前，&lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;我們&lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;先整理出幾個步驟：首先，我們將「小明」與「小明的爸爸」註冊為「小明在學資料」的觀察者。其次，設定「小明在學資料」裡的分數。然後，學期結束時，「小明在學資料」會結算被當科目，確認小明有沒有被二一。最後，學期結束時，「小明的在學資料」會自動通知「小明」與「小明的爸爸」，小明是否有被二一。&lt;/span&gt;&lt;br /&gt;以下是主程式：&lt;br /&gt;&lt;pre style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;class Main{&lt;br /&gt;   public static void main(String[] arg){&lt;br /&gt;       //小明的在學資料&lt;br /&gt;       StudentData studentData = new StudentData("小明");&lt;br /&gt;   &lt;br /&gt;       People ming = new People("小明本人");&lt;br /&gt;       People father = new People("小明的爸爸");&lt;br /&gt;       //學生資料加入觀察者&lt;br /&gt;       studentData.addObserver(ming);&lt;br /&gt;       studentData.addObserver(father);&lt;br /&gt;   &lt;br /&gt;       //設定成績&lt;br /&gt;       studentData.setScore("微積分", 59);&lt;br /&gt;       studentData.setScore("物理", 60);&lt;br /&gt;       studentData.setScore("計算機網路", 54);&lt;br /&gt;   &lt;br /&gt;       // 學期結束，結算被當科目&lt;br /&gt;       studentData.validateCredits();&lt;br /&gt;   }  &lt;br /&gt;}&lt;/pre&gt;接下來是表示人(小明本人、小明的爸爸)的類別，實作觀察者介面：&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;class People implements Observer{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    private String name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    public People(String name){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;        this.name = name;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    public void update(String message){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;        System.out.println(&lt;br /&gt;            name + " 收到["+ message +"]的訊息。");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;}&lt;/span&gt;&lt;/pre&gt;最後是表示「學生在學資料」的類別，實作被觀察者介面：&lt;br /&gt;&lt;pre style="font-family: times new roman;font-style: italic; color: rgb(102, 102, 102);"&gt;/** 在學學生資料*/&lt;br /&gt;class StudentData implements Observable{&lt;br /&gt;   private String name;&lt;br /&gt;    /** 使用LinkedList來儲存多個觀察者。 */&lt;br /&gt;   private List&amp;lt; Observer&amp;gt; observers =&lt;br /&gt;                    new LinkedList&amp;lt;Observer &amp;gt;();&lt;br /&gt;   private HashMap&amp;lt; String,Integer&amp;gt; scores =&lt;br /&gt;                    new HashMap&amp;lt;String, Integer&amp;gt;();&lt;br /&gt; &lt;br /&gt;   public StudentData(String name){&lt;br /&gt;       this.name = name;&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   public String getName(){&lt;br /&gt;       return name;&lt;br /&gt;   }&lt;br /&gt;   /** 設定成績*/&lt;br /&gt;   public void setScore(String subject, int score){&lt;br /&gt;       scores.put(subject, score);&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   /** 結算學分*/&lt;br /&gt;   public void validateCredits(){&lt;br /&gt;       int totalSubject = scores.size();    //全部科目數&lt;br /&gt;       int failSubject = 0;    //被當的科目數&lt;br /&gt;     &lt;br /&gt;         /** 尋訪整個HashMap，取出所有的值 */&lt;br /&gt;       for(int score: scores.values()){&lt;br /&gt;            //不到60分，累加被當的科目數 &lt;br /&gt;           if( score &amp;lt; 60)&lt;br /&gt;               failSubject++;&lt;br /&gt;       }&lt;br /&gt;         //若被當的科目數大於總科目數的一半&lt;br /&gt;       if( (totalSubject / 2) &amp;lt; failSubject )&lt;br /&gt;           notifyObservers("下學期不用繳註冊費。");&lt;br /&gt;       else&lt;br /&gt;           notifyObservers("下學期記得繳註冊費。");&lt;br /&gt; &lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   /** 通知所有觀察者*/&lt;br /&gt;   public void notifyObservers(String msg){&lt;br /&gt;        /** 尋訪整個List，取出所有觀察者 */&lt;br /&gt;       for(Observer observer : observers)&lt;br /&gt;           observer.update(msg);&lt;br /&gt;   }&lt;br /&gt;   /** 新增觀察者*/&lt;br /&gt;   public void addObserver(Observer observer){&lt;br /&gt;       observers.add(observer);&lt;br /&gt;   }&lt;br /&gt;   /** 移除觀察者*/&lt;br /&gt;   public void removeObserver(Observer observer){&lt;br /&gt;       observers.remove(observer);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="color: rgb(255, 0, 0);font-family:times new roman;" &gt;執行結果如下：&lt;/span&gt;&lt;br /&gt;&lt;div  style="background: black none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: rgb(200, 200, 200);font-family:times new roman;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;小明本人 收到[下學期不用繳註冊費。]的訊息。&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;小明的爸爸 收到[下學期不用繳註冊費。]的訊息。&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Observer模式的原理其實很簡單：只要在被觀察者的狀態被改變(ex.set方法被呼叫)或條件滿足時，經由Observer介面所定義的方法，將狀態改變的消息傳遞給已註冊的觀察者們。然而，Observer模式有相當多應用，例如著名的MVC架構模式即是根基於此模式。關於Observer模式的各種應用，將在之後的文章提到，請耐心等待。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-6210117411945938930?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/6210117411945938930/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2010/01/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6210117411945938930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6210117411945938930'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2010/01/blog-post.html' title='淺談設計模式之觀察者模式'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_15zvGmmKTdk/S1sPDD0X0oI/AAAAAAAAFY8/OZqzcvcKpeM/s72-c/observer+pattern.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-1884219595682977884</id><published>2009-07-23T15:35:00.000-07:00</published><updated>2009-07-24T12:42:46.641-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>What is “this”？</title><content type='html'>What is “this”？這是許多物件導向程式語言初學者的疑問。&lt;br /&gt;在許多物件導向語言中都存在著「this」關鍵字，舉凡Java、C++、C#都有這樣一個謎一般的關鍵字，在VB.Net與Ruby中則是以「self」之名存在著。某些非物件導向的程式語言如Javascript，甚至也提供「this」來模擬物件導向的特性。&lt;br /&gt;究竟「this」是天使的化身，還是地獄的使者？是什麼樣的力量促使他在物件導向的世界裡屹立不搖？其實，它沒那麼偉大，充其量只是個「第一人稱代名詞」。&lt;br /&gt;在解釋它存在的必要之前，我們必須先為一個人生難題找出解答：如何在不說「我」的情況下，用合理的文法表達「教授把我當了」？如果你說「教授把XXX當了」，這樣的句子很奇怪，像是說另一個和你同名同姓還被你爆料的可憐同學。如果你說「教授當了」，請問教授到底當了誰？如果你說「被教授當了」，聽起來合理，但這其實是把「我」省略的慣用句型，文法上不合理，因為缺乏主詞。&lt;br /&gt;不知道有沒有人可以找出答案，如果有請留言告訴我。無論如何，代名詞不是我的重點，我只是想證實第一人稱代名詞的必要性：若沒有第一人稱代名詞，我們很難用語言表達自己的存在，也很難做第一人稱敘述。&lt;br /&gt;在物件導向的世界裡也是一樣的。由於一個類別可以產生許多實體，就必須用一個代名詞來讓個別實體表達「我」，以區分和其他實體的不同。一個類別的實體就是用「this」表達「我」。&lt;br /&gt;&lt;br /&gt;例如以下程式碼：&lt;br /&gt;&lt;pre style="font-style: italic; font-family: times new roman;"&gt;class Student{&lt;br /&gt;    private int score;&lt;br /&gt;    Student(int s){&lt;br /&gt;        score = s; //A&lt;br /&gt;    }&lt;br /&gt;    public void say(){&lt;br /&gt;        if( this.score &gt; 59)  // B&lt;br /&gt;              System.out.println("教授讓我過了！");&lt;br /&gt;        else&lt;br /&gt;               System.out.println("教授把我當了！");&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] arg){&lt;br /&gt;        Student 好學生 = new Student(80);&lt;br /&gt;        Student 混學生 = new Student(40);&lt;br /&gt;        好學生.say();&lt;br /&gt;        混學生.say();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;在main中，產生兩個Student類別的實體，兩個實體say的結果不一樣，因為this.score的值不一樣。這樣就可以看出，每個new出來的實體都有自己的this，代表各自的實體。&lt;br /&gt;&lt;br /&gt;※B的this是可以省略的，因為是在同一個類別，Java編譯器會在編譯時自動加入this。如A的score也可以改為this.score。&lt;br /&gt;&lt;br /&gt;其實看下圖就一目了然：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_15zvGmmKTdk/Smk4ANwcFrI/AAAAAAAAFVk/Rrh_uwHpsCA/s1600-h/student_memory.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 294px;" src="http://4.bp.blogspot.com/_15zvGmmKTdk/Smk4ANwcFrI/AAAAAAAAFVk/Rrh_uwHpsCA/s400/student_memory.png" alt="" id="BLOGGER_PHOTO_ID_5361878407705269938" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;main方法的Stack Frame中，「好學生」與「混學生」參照分別參考到不同的Student實體，兩個Student實體的this參照也分別參考到自己從屬的實體。如此一來，每個實體就可以用this表達「我」。例如，我的score就是this.score。&lt;br /&gt;那麼你可能會有個疑惑：難道「this」存在的意義只是為了表達像this.score這種可以省略的語法嗎？「this」真正的好處在於，實體可以將自己傳遞給其他實體。&lt;br /&gt;&lt;br /&gt;為了解釋這點，我們定義一個Professor類別，並在Student類別裡加入getScore方法，如下：&lt;br /&gt;&lt;pre style="font-style: italic; color: rgb(51, 51, 51); font-family: times new roman;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;class Professor{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    public void grade(Student student){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        student.score = (int)(Math.random()*101);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;class Student{&lt;br /&gt;   ...&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;   Professor 叫獸 = new Professor();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    public int getScore(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        叫獸.grade(this); // C&lt;/span&gt;&lt;br /&gt;       &lt;span style="color: rgb(51, 102, 255);"&gt;return score;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    public static void main(String[] arg){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        Student 羔羊 = new Student(0);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        羔羊.getScore();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        羔羊.say();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;我們先產生一個Student的實體「羔羊」，並呼叫getScore方法。呼叫時，羔羊的實體就會傳入叫獸.grade()方法，並設定score。C的部分，就是Student實體將自身傳入叫獸.grade()方法的部分。其實這行程式碼，翻成中文就是「叫獸給我打分數。」「this」就是「我」！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-1884219595682977884?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/1884219595682977884/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/07/what-is-this.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1884219595682977884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1884219595682977884'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/07/what-is-this.html' title='What is “this”？'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_15zvGmmKTdk/Smk4ANwcFrI/AAAAAAAAFVk/Rrh_uwHpsCA/s72-c/student_memory.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-1835968537688942454</id><published>2009-07-08T17:18:00.000-07:00</published><updated>2009-07-08T19:51:36.510-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>執行緒同步化之時間怪獸</title><content type='html'>昨天終於把專題Server端的Database Connection Pool改好了。原本以為是Thread之間的Race condition，造成資料庫記錄取得之前，連線就被回收連線的Thread給close掉。後來才發現是自己沒把 java.sql.Connection的autoCommit設為false，造成Connection在還沒有被commit的狀態下就被放回 Connection Pool裡，時間一到就帶著沒送出的資料一起被回收。問題根本不在Thread的同步，而是我幾乎忘記有autoCommit這東西。&lt;br /&gt;不過，問題改好之後，發現更大的問題：速度超慢。更離譜的是，使用單執行緒的方式執行，竟然還比有快取的多執行緒池快10倍以上。昨天晚上看著 Profiler的分析到凌晨4點，仍然找不出問題在哪，只看到執行緒wait的頻率很高。白天上課一直恍神，完全無法理解老師在上什麼，不過可能也因為恍神太多，讓我在走回宿舍的路上精神飽滿，聽著&lt;a href="http://www.youtube.com/watch?v=tQNNIeFijSQ"&gt;Claudio Abbado指揮Lucerne Festival Orchestra演出的Mahler交響曲第二號&lt;/a&gt;，靈機一動想到了一個可能性：「會不會有人拿著互斥鎖，做一些很耗時間的工作？」回到宿舍看code，果如所料！&lt;br /&gt;&lt;br /&gt;試比較下列這兩段程式碼，你比較喜歡哪一種寫法？&lt;br /&gt;&lt;br /&gt;Code 1.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;synchronized(this){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    if(queue.isEmpty()){&lt;/span&gt;&lt;br /&gt;&lt;!-- --&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            if(connectionCount.get()&lt;&lt;!-- --&gt; maxConnectionCount){&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                conn = new&lt;br /&gt;                   DBConnection(this,getRawConnection());&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                connectionCount.incrementAndGet();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    else{&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;...&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;Code 2.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;synchronized(this){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    if(queue.isEmpty()){&lt;/span&gt;&lt;br /&gt;&lt;!-- --&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            if(connectionCount.get()&lt;&lt;!-- --&gt; maxConnectionCount){&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                newConn = true;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                connectionCount.incrementAndGet();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    else{...}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;if(newConn)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    conn = new DBConnection(this,getRawConnection());&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;一般而言，多數人都會選Code 1.，因為兩段程式碼功能一樣，Code1卻顯得比較簡潔直觀。然而，Code1就是我一開始寫的，很花時間的程式碼。&lt;br /&gt;&lt;br /&gt;Code2和Code1最大的差別在於Code 2把 &lt;span style="color: rgb(51, 51, 255);"&gt;conn = new DBConnection(this,getRawConnection()); &lt;/span&gt;從同步區塊取出。這麼做會讓效能增加數倍的原因是&lt;span style="color: rgb(51, 51, 255);"&gt;getRawConnection()&lt;/span&gt;操作太花時間。如果放在同步區塊，代表一次只有1個執行緒能夠呼叫這個方法。這個方法一次得花10秒鐘的時間去和遠端資料庫連繫，如果一次只有1個執行緒呼叫，則20個執行緒至少得花200秒。Code2的&lt;span style="color: rgb(51, 51, 255);"&gt;getRawConnection()&lt;/span&gt;呼叫因為是在同步區塊之外，能夠讓多個執行緒同時取用，就沒有這種問題。&lt;br /&gt;這次的教訓告訴我們，可以放在同步區塊的程式碼越少越好。至少，非必要的話，不要把怪獸放進去。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-1835968537688942454?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/1835968537688942454/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/07/blog-post_08.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1835968537688942454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/1835968537688942454'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/07/blog-post_08.html' title='執行緒同步化之時間怪獸'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-5212898369279886994</id><published>2009-07-07T01:22:00.000-07:00</published><updated>2009-07-07T01:47:25.079-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='美學運算'/><title type='text'>Digital Sun</title><content type='html'>今天終於把事情忙完，心血來潮就把上次的Digital Chaos拿來修改，想說改成動態的形式。後來想到不錯的點子，讓圖的半徑交互遞增遞減，動態畫出一張類似太陽的圖形，姑且就稱它為Digital Sun吧。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_15zvGmmKTdk/SlMGUSVyc7I/AAAAAAAAFTI/EYLcq25sCbM/s1600-h/digital+sun.png"&gt;&lt;img style="cursor: pointer; width: 398px; height: 400px;" src="http://1.bp.blogspot.com/_15zvGmmKTdk/SlMGUSVyc7I/AAAAAAAAFTI/EYLcq25sCbM/s400/digital+sun.png" alt="" id="BLOGGER_PHOTO_ID_5355631327464027058" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;這是截圖，所以沒有動畫。在Processing上執行會是圓心到圓周的文字交替增加，形成中心越來越密集的太陽。&lt;br /&gt;&lt;br /&gt;後來又加上一個細微旋轉，使圖形變成颶風：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_15zvGmmKTdk/SlMHAj5C7gI/AAAAAAAAFTQ/JmRMIdJjXw4/s1600-h/digital+hurrican.png"&gt;&lt;img style="cursor: pointer; width: 397px; height: 400px;" src="http://2.bp.blogspot.com/_15zvGmmKTdk/SlMHAj5C7gI/AAAAAAAAFTQ/JmRMIdJjXw4/s400/digital+hurrican.png" alt="" id="BLOGGER_PHOTO_ID_5355632088089554434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;程式碼：&lt;br /&gt;&lt;pre style="color: rgb(102, 102, 102);"&gt;int lineSize = 400;&lt;br /&gt;int wide = 5;&lt;br /&gt;int hei = 8;&lt;br /&gt;int fontSize = 16;&lt;br /&gt;int shadow_shift = 2; //文字殘影偏移量&lt;br /&gt;int amount = 50;&lt;br /&gt;int radius = amount;&lt;br /&gt;float angel = 0; // 一行的角度偏移量，設成0.3會變颶風。&lt;br /&gt;PFont font;&lt;br /&gt;boolean sw = true;&lt;br /&gt;void setup(){&lt;br /&gt;size(800,800);&lt;br /&gt;font = createFont("Geogreia",fontSize);&lt;br /&gt;textFont(font);&lt;br /&gt;background(0);&lt;br /&gt;}&lt;br /&gt;void draw(){&lt;br /&gt;if(radius == -amount)&lt;br /&gt;  sw = true;&lt;br /&gt;if(radius == amount)&lt;br /&gt;  sw = false;&lt;br /&gt;radius += sw? 2:-2;&lt;br /&gt;translate(width/2,height/2);&lt;br /&gt;for(int i = 1 ; i &lt;&lt;!-- --&gt;= 10*abs(radius); i+=5){&lt;br /&gt; int rand = (int)random(2);&lt;br /&gt; int num = (int)random(2);&lt;br /&gt; int shift = (int)random(8) *  (i/lineSize &gt;=1 ? -1:1);&lt;br /&gt; int x = i%lineSize+i/100*wide + shift;&lt;br /&gt; int y = (i/lineSize)*hei+ shift;&lt;br /&gt; float trans = 160+95*(shift/7);&lt;br /&gt; fill(255,trans);&lt;br /&gt; rotate((rand == 0? -shift:shift));&lt;br /&gt; rotate(angel);&lt;br /&gt; text(String.valueOf(num), x , y);&lt;br /&gt; if(shadow_shift != 0){ &lt;br /&gt;   fill(255,trans*0.5);&lt;br /&gt;   text(String.valueOf(num), x+shadow_shift,y+shadow_shift);&lt;br /&gt; }&lt;br /&gt; textFont(font,fontSize+(rand == 0 ? -shift:shift));&lt;br /&gt;}&lt;br /&gt; translate(width/-2,height/-2);&lt;br /&gt;}&lt;/pre&gt;後來仔細想想，也許它該叫「眾妙之門」。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:標楷體;" &gt;「無，為天地之始；有，為萬物之母。故常無，欲以觀其妙；常有，欲以觀其徼。此兩者，同出而異名，同謂之玄，玄之又玄，眾妙之門。」－《道德經》&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-5212898369279886994?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/5212898369279886994/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/07/digital-sun.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/5212898369279886994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/5212898369279886994'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/07/digital-sun.html' title='Digital Sun'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_15zvGmmKTdk/SlMGUSVyc7I/AAAAAAAAFTI/EYLcq25sCbM/s72-c/digital+sun.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-6872263201815366667</id><published>2009-07-01T16:46:00.000-07:00</published><updated>2011-06-02T10:04:09.271-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>物件繼承的物件觀點－轉型篇</title><content type='html'>這篇文章是&lt;a href="http://yensrule.blogspot.com/2009/06/blog-post_30.html"&gt;物件繼承的物件觀點&lt;/a&gt;一文的續集，將用物件的功能觀點圖來說明物件的強制轉型何時會成功。&lt;br&gt;首先，我們先釐清一些有關於物件轉型的概念。&lt;br&gt;在Java中，所有子類別的物件不需要強制轉型就能夠隱含轉換為父類別型態。因此以下程式碼皆能夠通過編譯，也能正常執行。&lt;br&gt;&lt;br&gt;&lt;span style="color: #3366ff; font-style: italic;"&gt;女人 欣郁 = new 女人();&lt;/span&gt; &lt;span style="color: #3366ff; font-style: italic;"&gt;&lt;br&gt;人類 路人甲 = 欣郁;&lt;/span&gt; &lt;span style="color: #3366ff; font-style: italic;"&gt;&lt;br&gt;人類 阿呆   = new 男人();&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a href="http://yensrule.blogspot.com/2009/07/blog-post.html#more"&gt;閱讀更多 »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-6872263201815366667?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/6872263201815366667/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/07/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6872263201815366667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/6872263201815366667'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/07/blog-post.html' title='物件繼承的物件觀點－轉型篇'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_15zvGmmKTdk/Sk7_UzsYX3I/AAAAAAAAFSg/WxTA9XyRujw/s72-c/passby_shin.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-7494906087981407706</id><published>2009-06-30T11:34:00.000-07:00</published><updated>2009-07-04T00:47:01.669-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>物件繼承的物件觀點</title><content type='html'>「欣郁是個人。」&lt;br /&gt;「欣郁生了孩子。」&lt;br /&gt;欣郁生了個孩子，表示欣郁是女人，會生孩子很正常。即使這兩句話並沒有提到欣郁是個女人，正常人也可以藉由常理推敲出最有可能的結論。但是，如果不加入過去的經驗，純粹從以上兩句話來推敲，則會得到「人會生孩子」這種以偏概全的結論。正常人會從常識中選擇合理的解釋，但對沒有常識的程式語言編譯器而言，這種結論是上述兩句話的正解。這就是自然語言與程式語言之間的鴻溝：有些東西你認為是常識，編譯器卻不懂你的意思。&lt;br /&gt;這篇文章要談的是，你如何正確地將上述兩句話依照&lt;a href="http://yensrule.blogspot.com/2009/06/blog-post_28.html"&gt;物件繼承的類別觀點&lt;/a&gt;一文中的類別圖規格轉換成Java語言。&lt;br /&gt;如果我們直接將上述兩句話逐句翻譯成Java程式碼：&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;「欣郁是個人。」 → &lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 欣郁 = new 人類();&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;br /&gt;「欣郁生了孩子。」 → &lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 孩子 = 欣郁.生產();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這兩行程式碼大有問題！&lt;br /&gt;首先，我們並沒有說清楚欣郁究竟是男人還是女人。如果欣郁是男人，那麼&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;欣郁.生產()&lt;/span&gt;&lt;/span&gt;就不合理。因此我們必須把程式碼改為：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 欣郁 = new 女人();&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 孩子 = 欣郁.生產();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這段程式碼看起來較合理，起碼我們已經說明了欣郁是個女人的事實。然而，這樣的程式碼仍然無法編譯成功！&lt;br /&gt;大家可能認為現在欣郁「事實上」是個女人，因此&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;欣郁.生產()&lt;/span&gt;&lt;/span&gt;理應合法，那為什麼仍然無法編譯通過？理由是，當你把「欣郁」變數宣告成「人類」型態時，我們就把欣郁的「女人」的特性忽略掉了。這就好像我們說「人類是一種動物，所以人類會覓食」時，是把人類一般化成動物，而忽略掉人類獨有的特性(例如交談)。反之，我們不會說「人類是一種動物，所以人類會交談」因為這句話代表「動物會交談，而人類是一種動物，所以人類會交談」這樣的邏輯當然是錯誤的。同樣的道理，「女人會生產」並不代表人類都會生產。現在如果把欣郁一般化成人類看待，則我們就不能去看她獨有的「生產」功能，只能看到人類共有的「交談」功能。人類的定義裡並沒有生產的功能，而欣郁是人類，&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;欣郁.生產()&lt;/span&gt;&lt;/span&gt;當然不合理。要讓這段程式碼能夠成功編譯，我們必須把欣郁當成女人看待，因此修改成：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;女人 欣郁 = new 女人();&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 孩子 = 欣郁.生產();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這樣的程式碼就合法了。&lt;br /&gt;要理解上面的解釋或許很費腦筋，畢竟不是每個人的邏輯都相當清楚，幸好我們可以使用&lt;a href="http://yensrule.blogspot.com/2009/06/blog-post_28.html"&gt;物件繼承的類別觀點&lt;/a&gt;一文中的功能觀點來清楚解釋每一個步驟。&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;new 人類();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;可以用下圖表示：&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_15zvGmmKTdk/SkprenQChQI/AAAAAAAAFRo/pZkcOaxRNFE/s1600-h/human_obj.png"&gt;&lt;img style="cursor: pointer; width: 291px; height: 230px;" src="http://1.bp.blogspot.com/_15zvGmmKTdk/SkprenQChQI/AAAAAAAAFRo/pZkcOaxRNFE/s400/human_obj.png" alt="" id="BLOGGER_PHOTO_ID_5353209280759760130" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0);"&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;※表示物件的功能觀點圖為了與表示類別的功能觀點圖作區分，使用較具立體感的顏色來表達「照類別規格產生的實體物件」的效果。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;※本文將不會去區別參照與指標，因「指標」講起來比較傳神。&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255); font-style: italic;"&gt;人類 欣郁 = new 人類();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;則可以表達為「欣郁指標」指向「人類物件」：&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_15zvGmmKTdk/SkpuvqPY48I/AAAAAAAAFR4/YJVgup_01pU/s1600-h/shin_human_obj.png"&gt;&lt;img style="cursor: pointer; width: 303px; height: 245px;" src="http://3.bp.blogspot.com/_15zvGmmKTdk/SkpuvqPY48I/AAAAAAAAFR4/YJVgup_01pU/s400/shin_human_obj.png" alt="" id="BLOGGER_PHOTO_ID_5353212872154997698" border="0" /&gt;&lt;/a&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_15zvGmmKTdk/SkpuvqPY48I/AAAAAAAAFR4/YJVgup_01pU/s1600-h/shin_human_obj.png"&gt;&lt;/a&gt;&lt;br /&gt;現在就可以清楚看到&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;欣郁.生產()&lt;/span&gt;&lt;/span&gt;是不合法的，因為圖中的人類物件根本沒有「生產」功能。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;那麼，如果是這行程式碼，該怎麼解釋呢？&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;人類 欣郁 = new 女人();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;如下圖：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_15zvGmmKTdk/SkrDDkQzYZI/AAAAAAAAFSA/TMHIOy7RaNk/s1600-h/woman_obj.png"&gt;&lt;img style="cursor: pointer; width: 327px; height: 250px;" src="http://2.bp.blogspot.com/_15zvGmmKTdk/SkrDDkQzYZI/AAAAAAAAFSA/TMHIOy7RaNk/s400/woman_obj.png" alt="" id="BLOGGER_PHOTO_ID_5353305573124432274" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;※在此不管JVM內是否這麼實作，先從邏輯的角度剖析。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255); font-style: italic;"&gt;new 女人()&lt;/span&gt;產生的雖是女人物件，人類型態的欣郁指標卻是指向女人物件中屬於人類的部分，&lt;span style="color: rgb(51, 51, 255); font-style: italic;"&gt;欣郁.生產()&lt;/span&gt;也就不合法，因為指標所指向的物件仍然不具有「生產」功能。&lt;br /&gt;根據上述畫圖的原則，很自然可以推出下面這行程式碼代表的意義：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;女人 欣郁 = new 女人();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_15zvGmmKTdk/SkrFbnznNzI/AAAAAAAAFSI/ghkR_yyOSHA/s1600-h/shin_woman_obj.png"&gt;&lt;img style="cursor: pointer; width: 327px; height: 254px;" src="http://2.bp.blogspot.com/_15zvGmmKTdk/SkrFbnznNzI/AAAAAAAAFSI/ghkR_yyOSHA/s400/shin_woman_obj.png" alt="" id="BLOGGER_PHOTO_ID_5353308185415857970" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;由於欣郁指標現在是女人型態，指向女人物件的整個區塊，&lt;span style="color: rgb(51, 51, 255); font-style: italic;"&gt;欣郁.生產()&lt;/span&gt;就變得合法。&lt;br /&gt;同樣的道理也能套用在物件的轉型上，將在&lt;a href="http://yensrule.blogspot.com/2009/07/blog-post.html"&gt;下篇文章&lt;/a&gt;說明。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-7494906087981407706?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/7494906087981407706/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post_30.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/7494906087981407706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/7494906087981407706'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post_30.html' title='物件繼承的物件觀點'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_15zvGmmKTdk/SkprenQChQI/AAAAAAAAFRo/pZkcOaxRNFE/s72-c/human_obj.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-2791997719006751821</id><published>2009-06-28T16:11:00.000-07:00</published><updated>2010-10-30T10:13:47.687-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>物件繼承的類別觀點</title><content type='html'>從物件導向的術語來看，物件繼承是一種 「is a」的關係，但我個人比較偏好解釋成「is a kind of」，也就是「是一種」的關係，例如，男人是一種人類；女人是一種人類；人類是一種動物。這樣的形容比較精確，否則很容易和物件混淆。例如我們說，「欣郁是個人」，並不是說欣郁是人的子類別，而是說欣郁是人的一個物件，因此有必要釐清語意上的模糊。&lt;div&gt;將「男人是一種人類」、「女人是一種人類」、「人類是一種動物」的關係與特性以UML類別圖描述，則如下：&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_15zvGmmKTdk/SkhNUt73qBI/AAAAAAAAFRE/nrcv8tQvVTA/s400/Pad.png"&gt;&lt;img src="http://4.bp.blogspot.com/_15zvGmmKTdk/SkhNUt73qBI/AAAAAAAAFRE/nrcv8tQvVTA/s400/Pad.png" style="cursor: pointer; width: 250px; height: 400px;" alt="" id="BLOGGER_PHOTO_ID_5352613175453263890" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;從類別圖的表示中，我們可以很清楚看見類別的階層關係。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;一般而言，我們會很直觀的把上述類別圖轉換為如下的定義域圖，將每一個類別的定義視為一個集合。&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_15zvGmmKTdk/SkhRa8t9N4I/AAAAAAAAFRU/CvUiCQdot_8/s400/define_field.png"&gt;&lt;img src="http://3.bp.blogspot.com/_15zvGmmKTdk/SkhRa8t9N4I/AAAAAAAAFRU/CvUiCQdot_8/s400/define_field.png" style="cursor: pointer; width: 400px; height: 294px;" alt="" id="BLOGGER_PHOTO_ID_5352617680547166082" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;但是我得告訴你一個壞消息：從這種角度思考，對物件導向概念的釐清沒什麼幫助。原因是：你最多只能從這張圖看出男人與女人處於類別階層的何種位階。物件導向著重的是類別所提供的操作，因此你最好將你的角度顛倒過來，像下圖一樣改為從功能性的角度去思考每個類別提供什麼樣的操作。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_15zvGmmKTdk/SkhYJKaLM4I/AAAAAAAAFRc/4-kAKEGrz20/s1600-h/define_figure.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 156px;" src="http://2.bp.blogspot.com/_15zvGmmKTdk/SkhYJKaLM4I/AAAAAAAAFRc/4-kAKEGrz20/s400/define_figure.png" alt="" id="BLOGGER_PHOTO_ID_5352625071566041986" border="0" /&gt;&lt;/a&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_15zvGmmKTdk/SkhYJKaLM4I/AAAAAAAAFRc/4-kAKEGrz20/s1600-h/define_figure.png"&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;從這張圖你可以看見，男人與女人的功能裡包含著男人或女人特有的功能，加上人類及動物的功能。這樣你就不會期望男人與女人在交談上必須有一樣的表現，因為雖然交談是「人類」類別提供的功能，現在男人與女人都有自己的「人類」功能區塊，雖然都有「人類」的功能，卻可以提供不同的實作。這種Overriding(覆載)的概念，從功能性的角度才看得出來。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-2791997719006751821?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/2791997719006751821/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post_28.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/2791997719006751821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/2791997719006751821'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post_28.html' title='物件繼承的類別觀點'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_15zvGmmKTdk/SkhNUt73qBI/AAAAAAAAFRE/nrcv8tQvVTA/s72-c/Pad.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-88967742323198848</id><published>2009-06-28T02:21:00.000-07:00</published><updated>2009-07-07T23:57:38.851-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='物件導向技術之詮釋學'/><title type='text'>Dependency Injection</title><content type='html'>Dependency Injection(依賴注入，簡稱DI)是物件導向技術中常被用來降低模組間耦合度的做法，Martin Fowler首先在他的&lt;a href="http://martinfowler.com/articles/injection.html#InversionOfControl"&gt;Inversion of Control Containers and the Dependency Injection pattern&lt;/a&gt;一文中使用了這個詞，並定義了三種型式的DI，分別是type 1：Interface Injection、type 2：Setter Injection及type 3：Constructor Injection，後來又由&lt;a href="http://www.picocontainer.org/"&gt;picocontainer&lt;/a&gt;定義了更多種類的DI。那些DI，其實我也不知道詳細情形為何，也懶得知道。無論如何，DI的用途就是「將模組之間的相依性從程式實作中抽離」。這樣說或許很抽象，但我們生活中其實充滿DI的影子。例如，每個MP3 Player一定需要電池才能運作，有些MP3的電池是內建的，無法更換；有些使用3號或4號鹼性電池，替換很方便。使用內建電池的MP3 Player，由於電池相依於MP3 Player的內部實作，如果之後電池壞掉，就只能買一台新的。而使用標準電池的MP3 Player，即使電池壞掉，只要到7-11買一副新的電池，馬上就能夠使用。同樣的道理也適用於軟體設計：萬一某天發現軟體中的一個類別有bug，究竟是要整個軟體都改過，還是只需要改有bug的類別？這樣我們就能歸納出一個結論：類別和MP3Player的電池一樣，最好能夠想換就換。廢話不多說，我們直接寫個Java MP3Player程式來看看。&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;class MP3Player{&lt;br /&gt;private NormalBattery battery = new NormalBattery();&lt;br /&gt;public void play(){&lt;br /&gt;    battery.usePower();&lt;br /&gt;}&lt;br /&gt;public int getBatteryPower(){&lt;br /&gt;    return battery.getPower();&lt;br /&gt;}&lt;br /&gt;public static void main(String... arg){&lt;br /&gt;    MP3Player player = new MP3Player();&lt;br /&gt;    /** 使用至沒電為止 */&lt;br /&gt;    while(player.getBatteryPower()&gt;0){&lt;br /&gt;        player.play();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;class NormalBattery{&lt;br /&gt;private int power = 100;    //預設電力100&lt;br /&gt;public int getPower(){&lt;br /&gt;    return power;&lt;br /&gt;}&lt;br /&gt;public void usePower(){&lt;br /&gt;    power--;            //每使用一次就遞減&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;Program A.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;以上是代表MP3 Player與電池的類別。注意在MP3Player類別裡，battery欄位的初始值已經指名了要使用的電池是NormalBattery。這意味著如果哪天我們發現NormalBattery類別已經無法滿足我們的需求，想替換的話就必須連MP3Player類別一起更改。現在這麼看可能覺得只是小事，但試想若有10個類別同時使用到NormalBattery，你得花多少時間在這種猴子也能做的瑣碎工作上？&lt;br /&gt;為了不讓身為人類的你退化成猴子，我們還是將上面的程式修改一下，並加入一個Battery介面。&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;interface Battery{&lt;br /&gt;  int getPower();&lt;br /&gt;  void usePower();&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;class MP3Player{&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;   private Battery battery;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;   public MP3Player(Battery battery){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;       this.battery = battery;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;   }&lt;/span&gt;&lt;br /&gt;public static void main(String... arg){&lt;br /&gt;    /** 建構 player時將NormalBattery傳入當參數 */&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;       MP3Player player = new MP3Player(new NormalBattery());&lt;/span&gt;&lt;br /&gt;    ....&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;class NormalBattery implements Battery&lt;/span&gt;{&lt;br /&gt;    ....&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;Program B.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;這Program B.裡，我們先將電池所共有的功能抽象成一個介面，並讓NormalBattery去實作它。在MP3Player類別裡，則讓battery欄位的值在建構時才由傳入的參數決定。如此一來，使用何種Battery介面的實作的決定權，便從MP3Player類別的實作者手中，轉移到MP3Player使用者的手上。就好比使用者可以隨意更換MP3 Player的電池，而不是取決於MP3 Player的製造商。&lt;br /&gt;但是萬一MP3 Player用到一半，突然想把電池拆掉，又或者，一開始就不想要裝電池，該怎麼辦？如果是用建構子傳入參數的方式，因為沒有提供修改battery的方法，也強制MP3Player的使用者在建構MP3Player時就必須把battery的實體傳入。這種方式在某些情況下顯然不適用，因此我們改採另一種方法：不使用建構子傳參數，而是增加Setter方法。&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;class MP3Player{&lt;br /&gt;  private Battery battery;&lt;br /&gt;  public MP3Player(){}&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;   public void setBattery(Battery battery){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;       this.battery = battery;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;   }&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;  public static void main(String... arg){&lt;br /&gt;      MP3Player player = new MP3Player();&lt;br /&gt;      /** 設定電池 */&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;       player.setBattery(new NormalBattery());&lt;/span&gt;&lt;br /&gt;      ....&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;class NormalBattery implements Battery{&lt;br /&gt;    ....&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;Program C.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;Program C.中把改為不在建構子傳參數，而是去將參數傳入新增的setBattery()方法。這種作法在建構子參數太多的時候相當有用，特別是那些可以省略的參數。&lt;br /&gt;&lt;br /&gt;介紹到這裡，看似頗為人滿意，終於可以快樂大結局了。但是，在這個能源耗竭的時代，我們必須思考著如果有一天，MP3 Player的價錢會跟電池差不多，只更換電池就顯得沒有意義，連MP3 Player也必須要可以替換才行。為了因應這種變態的要求，MP3 Player廠商終於決定不再販賣MP3 Player，宣布轉型為MP3 Player出租商，改成以服務的方式收取費用。&lt;div&gt;為了因應石油不足對產業結構產生的衝擊，物件導向技術也有一套作法，讓你不需要去理會程式碼寫了什麼或怎麼使用，只要改一改訂單，MP3 Player和電池就送到府上供你使用。這種做法必須仰賴介面，將各個實作類別抽象化，因此必須新增 Player介面。&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;class NormalBattery implements Battery{....}&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;interface Battery{&lt;br /&gt;   ....&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;interface Player{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    void setBattery(Battery batery);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    void play();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    int getBatteryPower();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;class MP3Player implements Player&lt;/span&gt;{&lt;br /&gt;   private Battery battery;&lt;br /&gt;   public MP3Player(){}&lt;br /&gt;   public void setBattery(Battery battery){....}&lt;br /&gt;   public void play(){....}&lt;br /&gt;   public int getBatteryPower(){....}&lt;br /&gt;}&lt;br /&gt;class NormalBattery implements Battery{....}&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;import java.io.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;class Main{&lt;br /&gt;   public static void main(String... arg)throws Exception{&lt;br /&gt;      Properties props = new Properties();&lt;br /&gt;      /** 從config.txt檔案中讀出屬性 */&lt;br /&gt;      props.load(new FileInputStream("config.txt"));&lt;br /&gt;      /** 動態載入類別 */&lt;br /&gt;      Class playerClass =&lt;br /&gt;               Class.forName(props.getProperty("player"));&lt;br /&gt;      Class batteryClass =&lt;br /&gt;               Class.forName(props.getProperty("battery"));&lt;br /&gt;      Player player = (Player)playerClass.newInstance();&lt;br /&gt;      Battery battery = (Battery)batteryClass.newInstance();&lt;br /&gt;      /** 設定電池 */&lt;br /&gt;      player.setBattery(battery);&lt;br /&gt;      /** 使用至沒電為止 */&lt;br /&gt;      while(player.getBatteryPower()&gt;0){&lt;br /&gt;          player.play();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;config.txt→&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;player:MP3Player&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;battery:NormalBattery&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;Program D.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;由於Program D.要凸顯不需要知道MP3Player內部實作的特性，因此把main方法移到Main類別裡。現在整個主程式完全看不到MP3Player和NormalBattery的蹤影，但程式還是會呼叫MP3Player的setBattery()方法，並將NormalBattery的實體傳入。程式依賴於config.txt的設定，如果想要修改Player或Batter的實作，只需要將實作類別編譯好，接著修改config.txt的內容就可以了。這種方法很明顯要比前面的方法還要有彈性的多，然而如果實作是一些現成的框架提供的介面，在抽離框架時就必須大量修改，代價挺高。由於這種方法有很高的侵入性，大多框架還是使用前面兩種作法。&lt;br /&gt;&lt;br /&gt;一開始曾經提到，Martin Fowler曾經定義出三種DI的型態。 Program B.是屬於type 3，Constructor Injection； Program C.是type 2, Setter Injection； Program D.為type 1, Interface Injection。定義得那麼複雜，其實一點也不難。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-88967742323198848?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/88967742323198848/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/06/dependency-injection.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/88967742323198848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/88967742323198848'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/06/dependency-injection.html' title='Dependency Injection'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-5470539652970891694</id><published>2009-06-27T20:25:00.000-07:00</published><updated>2009-06-28T01:18:09.538-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='美學運算'/><title type='text'>Digital Chaos</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_15zvGmmKTdk/SkbjXv3oMGI/AAAAAAAAFNU/Ggf5bq1Rafw/s1600-h/digitalChaos.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 396px; height: 400px;" src="http://3.bp.blogspot.com/_15zvGmmKTdk/SkbjXv3oMGI/AAAAAAAAFNU/Ggf5bq1Rafw/s400/digitalChaos.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5352215204302696546" /&gt;&lt;/a&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_15zvGmmKTdk/SkbjXv3oMGI/AAAAAAAAFNU/Ggf5bq1Rafw/s1600-h/digitalChaos.jpg"&gt;&lt;/a&gt;原本Logo右邊那個數碼圖是打算用Fireworks來畫的，直到開始畫才覺得這樣太浪費時間，又不見得好看，就想到用Processing來做，結果效果出乎意料的好。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;原始碼：&lt;pre&gt;int lineSize = 200;&lt;br /&gt;int wide = 4;&lt;br /&gt;int hei = 8;&lt;br /&gt;int fontSize = 16;&lt;br /&gt;int shadow_shift = 0;&lt;br /&gt;void setup(){&lt;br /&gt;   size(800,800);&lt;br /&gt;   PFont font = createFont("Geogreia",fontSize);&lt;br /&gt;   textFont(font);&lt;br /&gt;   background(0);&lt;br /&gt;   translate(width/2,height/2);&lt;br /&gt;   for(int i = 1 ; i &lt;&lt;!-- --&gt;= 5000; i+=5){&lt;br /&gt;   int rand = (int)random(2);&lt;br /&gt;   int num = (int)random(2);&lt;br /&gt;   int shift = (int)random(8) *  (i/lineSize &gt;&lt;!-- --&gt;=1 ? -1:1);&lt;br /&gt;   int x = i%lineSize+i/100*wide + shift;&lt;br /&gt;   int y = (i/lineSize)*hei+ shift;&lt;br /&gt;   float trans = 160+95*(shift/7);&lt;br /&gt;   fill(255,trans);&lt;br /&gt;   rotate((rand == 0? -shift:shift));&lt;br /&gt;   text(String.valueOf(num), x , y);&lt;br /&gt;   fill(255,trans*0.5);&lt;br /&gt;   text(String.valueOf(num), x+shadow_shift,y+shadow_shift);&lt;br /&gt;   rotate((rand != 0? -shift:shift));&lt;br /&gt;   textFont(font,fontSize+(rand == 0 ? -shift:shift));&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-5470539652970891694?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/5470539652970891694/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/06/digital-chaos.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/5470539652970891694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/5470539652970891694'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/06/digital-chaos.html' title='Digital Chaos'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_15zvGmmKTdk/SkbjXv3oMGI/AAAAAAAAFNU/Ggf5bq1Rafw/s72-c/digitalChaos.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6300120481261832269.post-4448612308403858098</id><published>2009-06-27T16:15:00.000-07:00</published><updated>2009-06-27T21:53:59.413-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='瞎掰'/><title type='text'>言式法則</title><content type='html'>一直以來，我都想要開一個網誌來存放我那些用完即刪除的小程式，以及那些突然出現的關於程式設計的好點子。這個願望在教授冷酷無情的摧殘與自己無窮無盡的怠惰的雙重夾攻之下，每次都胎死腹中，不了了之。今天在500cc的咖啡因刺激之下，我終於下定決心按下建立網誌的選項。&lt;div&gt;總而言之，這網誌產生了，而這裡將會是我存放一些程式設計心得以及小作品的地方，可能偶爾會出現一些評論。如果你對文章不甚同意或有疑問，你第一件可以做的事情就是留言，然而喜歡保持網誌整潔的我，不能忍受網誌被留言霸佔，因此你的留言將不會出現在網誌上，系統會直接寄送到我的信箱，到時我會看到。如果你完全不想留言，你可以選擇馬上離開，這是乾脆又容易，同時也最被鼓勵使用的選項。&lt;/div&gt;&lt;div&gt;至於網誌的名字為什麼叫做言式法則？主要原因是作者個人對名字的喜好，次要原因則是這網誌裡的所有文章都是試驗性質的。如果你把言式兩個字合併起來看，就成為了「試」。沒錯，這個網誌就是秉持著試試看的精神創建的，因此若你發現這裡的方法對你無效，或者根本就錯了，請不要大驚小怪，就當和我一起試試看那些鬼東西，然後把問題回報給我知道，不然就乾脆離開，當作沒這回事。&lt;/div&gt;&lt;div&gt;這網誌裡的所有文章都不會標示「版權所有，翻印必究」的噁心標示，但這並不表示這裡的 一字一句都可以任意擷取，而是著作權根本是常識，如果要轉載或引用請一定要註明出處。其餘法律規章請參考&lt;a href="http://zh.wikipedia.org/w/index.php?title=%E5%90%88%E7%90%86%E4%BD%BF%E7%94%A8&amp;amp;variant=zh-tw"&gt;Wikipedia之合理使用條文&lt;/a&gt;。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;很好，它終於誕生了。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6300120481261832269-4448612308403858098?l=yensrule.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yensrule.blogspot.com/feeds/4448612308403858098/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/4448612308403858098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6300120481261832269/posts/default/4448612308403858098'/><link rel='alternate' type='text/html' href='http://yensrule.blogspot.com/2009/06/blog-post.html' title='言式法則'/><author><name>Frederich</name><uri>http://www.blogger.com/profile/08636018927252532716</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/--2X57JXJtck/TbkYwB1jXEI/AAAAAAAAFgk/gFQHaBu57ic/s1600/5652843-big6.jpg'/></author><thr:total>0</thr:total></entry></feed>
