生平第一次知道 Aeron Chair 是因為吉米丘在 2005 年分享的這篇文章,當時就覺得如果以後有預算了,一定要買一把 Aeron Chair 回來坐。因為長時間在電腦前面的人,往往容易因為太過於專注而忘記起來運動。維持同一個姿勢久了就容易造成腰酸背痛,四肢僵硬的症狀,
然後不知不覺就過了四年 (快轉到 2009 年)
Continue reading “Herman Miller – Aeron Chair”
_老屁孩_
生平第一次知道 Aeron Chair 是因為吉米丘在 2005 年分享的這篇文章,當時就覺得如果以後有預算了,一定要買一把 Aeron Chair 回來坐。因為長時間在電腦前面的人,往往容易因為太過於專注而忘記起來運動。維持同一個姿勢久了就容易造成腰酸背痛,四肢僵硬的症狀,
然後不知不覺就過了四年 (快轉到 2009 年)
Continue reading “Herman Miller – Aeron Chair”
不能信任的東西:韓國發明、英國研究、中國製造、台灣報導。
— 轉自網路
在寫程式的時候,Unit Test 是頗為重要的一環,Working Effectively with Legacy Code 裡面甚至提出了一個概念:「Legacy Code is Code Without Tests」
呃,所以,還是直接看 code 好了…
以下示範 Dependency Injection 的寫法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php class foo { /** * foo_run 這個方法會把數字 $i 開更號乘以 10, 以前老師都這樣調整成績的 */ public function foo_run($i) { $b = new bar(); $result = $b->bar_run($i); // 把 $i 放進去 bar_run() 處理取得平方根 $sum = $result * 10; return $sum; } } class bar { public function bar_run($i) { $result = ''; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://example.com/get_sqrt/$i"); // 呼叫 Web Service ,取得 $i 的平方根 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); curl_close($ch); return $result; } } $foo = new foo(); $foo->foo_run(); |
以本例來說: foo 類別裡面的 foo_run() 方法是無法被測試的,因為在這個方法裡面有使用 new bar() 建立了一個 $b 物件,並且執行 $b->bar_run() 。我們可以看出來這個 $b->bar_run() 會呼叫 Web Service 。所以當我們執行到 foo_run() 的時候,可能會因為環境的因素而無法測試。
這種程式之間的相依性問題往往會對 Unit Test 造成很大的困擾。如果沒有排除程式之間的相依性,就很容易會讓我們在進行測試時卡住。(除了呼叫 Web Service 以外,也可能是存取資料庫、寫檔案、或是做其他動作。而這些動作可能會因為不同的環境而讓程式無法執行。)。
所以,既然 bar 類別並不在我們需要的測試範圍內,我們就可以透過 Dependency Injection 來降低程式之間的相依性。
假設我們只要測試 foo 類別裡面的 foo_run() 方法,而不想測試 bar 類別的 bar_run() 方法,那可以改採取以下的策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?php class foo { protected $bar; // 多寫了一個方法 set_bar(); 讓 Bar 物件可以從外面傳進來 public function set_bar(Bar $bar) { $this->bar = $bar; } public function foo_run($i) { $result = $this->bar->bar_run($i); $sum = $result * 10; return $sum; } } class bar { public function bar_run($i) { $result = ''; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://example.com/get_sqrt/$i"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); curl_close($ch); return $result; } } $foo = new foo(); $bar = new bar(); // 把 $bar 物件從外面傳進去 $foo->set_bar($bar); $foo->foo_run(); |
這個方式,讓 $bar 物件得以在外面產生,並且注入到 foo 類別中,從此我們可以依照不同的環境建造出不同的 bar 物件。
要建立一個物件,我們至少要寫好幾行 code 來宣告它才會動,而為了測試寫這些 code 就顯得不太聰明,於是 PHPUnit 提供了 Mock Object 的功能。假設我們在 PHPUnit 中要測試上面的 foo 類別,可以採取以下的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
require_once 'foo.inc'; class fooTest extends PHPUnit_Framework_TestCase { public function testRunFoo() { $foo = new foo(); $mock_bar = $this->getMock('bar', array('bar_run')); $expected_result = sqrt($i); $mock_bar->expects($this->any()) ->method('bar_run') ->will($this->returnValue($expected_result)); $foo->set_bar($mock_bar); // 把 Mock Object 傳進去 $result = $foo->foo_run(36); $this->assertEquals($result, 60); } } |
另外也可以針對測試環境做一些調整…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class foo { protected $bar = null; public function set_bar(Bar $bar) { $this->bar = $bar; } // 這邊多了一個 get_bar() public function get_bar() { if(is_null($this->bar)) { $this->bar = new bar(); } } public function foo_run($i) { $result = $this->bar->bar_run($i); $sum = $result * 10; return $sum; } } |
我們可以在 foo 類別中,產生一個新的 get_bar() 方法,當要真正要使用 bar 的時候,再呼叫一次 $this->get_bar() 來產生所需要的物件。
假設之前沒有被 $this->set_bar() 做過 Dependency Injection 的話,就會產生預期中的 bar 物件。
以上是簡單的範例介紹,用簡單的方法改寫原本無法被測試的程式 🙂
在真‧三國無雙6 遊戲中,「印」是指特別的能力,例如體力增加、攻擊力增加、防禦力增加、無雙+1…等等。
武將可以將「印」裝配到武器上,即可得到該「印」的效果,每種武器可以裝配印的數量不同,最少兩個,最多五個。
快速練印的方法是
1. 進入戰史模式,劇本選擇三國無雙
2. 武將選擇諸葛亮、難度選擇天堂。
3. 主要武器選擇要練印的武器 (印獲得速度較快)
4. 次要武器裝備”印獲得促進”
5. 將要練印的武器寄存在打鐵店 (印獲得速度較慢)
6. 在三國無雙的地圖中,先到畫面中間吃掉 Life UP + 10
7. 每到一個領地,直接衝到敵方主帥旁邊,等其餘敵方武將聚集之後一直放無雙即可,注意別讓敵方主帥死得比敵方武將快,以免該領地的 NPC 過早被系統自動回收。
8. 從右上角開始逆時針一路打到右下角,最後再收拾掉呂布。
打這關得好處是武將夠多,尤其最後缺幾個印想要儘快收集完整時候,用這招練印非常快。