2016年7月19日 星期二

Learning JavaScript Design Patterns 筆記 6

The Mixin Pattern

不透過繼承的方式,將其它物件的部分 method 「拿來使用」。此模式主要目的是「程式碼重用」。但也因為如此,會讓物件關係變得比較混亂。因此,如果沒有必要,這模式最好少使用。可能的使用時機是,「除錯」或是,太複雜的原程式碼只能透過借用的方式處理。

使用 underscorejs 的 extend

// 要被「借用method」的物件
var myMixins = {
  moveUp: function(){ /* ... */ },
  moveDown: function(){ /* ... */ },
  stop: function(){ /* ... */ }
};

// 借用方
function CarAnimator(){
  this.moveLeft = function(){ /* ... */ };
} 
 
// 將 myMixins 的方法給借用方
_.extend( CarAnimator.prototype, myMixins );
 
var myAnimator = new CarAnimator();
// 使用「借用」的method
myAnimator.moveLeft();
myAnimator.moveDown();
myAnimator.stop();


另外此部分有提供只借用部分method的方式,但將欲借用的method,當作第三個參數以後傳入。可是這個function只有定義兩個參數,雖然javascript可以用這樣的方式來接收「多」出來的參數作處理,但最好還是定義第三個參數,直接處理比較好。免得日後還要猜第三個未定義的參數,到底是什麼意思。

// t: targetClass, s:sourceClass, m:methods array
function augment(t, s, m) {
    // 只需部分 methods
    if (m) {
        for (var i=0; i < m.length; i++ ) {
            t.prototype[m[i]] = s.prototype[m[i]];
        }
    }
    // 將 s 的 all methods 傳給 t
    else {
        for (var mName in s.prototype ) {
            if ( !Object.hasOwnProperty.call(t.prototype, methodName) ) {
                t.prototype[mName] = s.prototype[methodName];
            }
        }
    }
}

// 使用方式
augment(target, source, ["methodA", "methodB"]);
augment(target, source);

2016年7月17日 星期日

Learning JavaScript Design Patterns 筆記 5

The Command Pattern

原文中,此部分只是把一個存在的物件,另外包起來而已,應參考Command pattern的實作方式。分成下列三個物件:
  • 管控命令的物件(Invoker):
    • 加入、記錄、執行Command的物件。
    • 可將 Command 的實例「抽出」成一個 String 對應的參數,如此在 Client 端就完全不需知道實際使用到的 Receiver Class
  • 命令物件(Command):
    • 均實作Command Interface,有共同的一個method -- execute
    • 由 Invoker 呼叫 execute。
  • 執行命令的物件(Receiver)
    • 在 Command 的 execute 中,實際運作的物件。
    • 這些物件可能有不一樣的constructor,不一樣的參數設定,但都需在 Command execute 之前,建構完成。
範例可直接參考 Wiki 
圖例可參考 Google 查詢


The Facade Pattern 

「表面」模式 ,將「特定」物件複雜的API,透過表面模式,包裝成一個較易於了解和使用的物件。如 JQuery 把許多複雜的判斷 DOM 操作,變成單一 method 呼叫,例如 $(el).css(),$(el).animate()。

表面模式的使用,要從 Client 的角度來看,由於複雜物件及 API ,在使用上可能需一步一步設定,才能達到「某」特定功能。而對 Client 端,它「只」需這「某」特定功能。故透過表面模式,將此「某」特定功能「包」起來,讓 Client 直接使用。

效能注意,以JQuery為例,直接使用 getElementById("identifier") 比 $("#identifier") 快很多很多

發射飛彈的流程 ,每一層都可用表面模式
  • 對發射控制官而言,它需要長官確認,核對密碼,插入Key等等一連串動作,最後讓長官按發射鈕。但他不用去管實際飛彈要發射或發射時的一連串機械動作。
  • 對長官而言,他只需要總統的命令,將密碼提供給發射官,最後按按鈕。
  • 對總統而言,只是打個電話,要求發射飛彈。


The Factory Pattern

不直接使用 new ,而是透過這個 Factory pattern 來取得物件實例,何時使用:
  • 當建立此物件實例的過程很繁雜
  • 需依環境需求,同一物件需有不同的參數設定時
  • 當共用相同properties的許多小物件時
  • 建立同interface但不同的實例實作時
Abstract Factory Pattern v.s. Factory Pattern
  • Abstruct Factory Pattern 將物件的生成,用一個Class處理。因此個別實作的 Factroy 可產生個別的物件。
  • Factory Pattern 將物件的生成,用一個Method處理,所以只能針對特定物件的生成作處理。 
參考 Abstract Factory

2016年7月12日 星期二

Learning JavaScript Design Patterns 筆記 4

The Mediator Pattern

透過中介者,將多個物件的運作及處理流程寫在其中,例如飛機彼此的通訊,全通過塔台統一處理,而不是由個別的飛機互相溝通。

Mediator:
  • 處理流程主要由此處理
  • 協調個別執行的物件
  • 此模式使用到的物件,彼此多少有關係,才會有處理流程可放在Mediator中

Event Aggregation:
  • 處理流程主要藉由 event 傳給由各個Subscriber處理
  • 本身不含處理流程
  • 像是 JQuery 的 on,可以讓個別的 HTML 元件,透過這個 on 而有自己的 event 處理機制
  • 物件彼此間較無直接關連


The Prototype Pattern

The GoF refer to the prototype pattern as one which creates objects based on a template of an existing object through cloning.

使用 Object.create 的方式,在原有的程式(物件)上,產生新的物件。
實作方式應採用 Javascript OOP 最佳實作 ,此篇主要介紹 prototype 的概念。

Javascript 標準及一些 API

You-Dont-Need-jQuery
You-Dont-Need-Lodash-Underscore

由於最近幾年,隨著 Browser 「再次」大戰 ,Google Chrome 取得了主導的地位。而 Javascript 也在「這幾年」開始有進一步的標準,及許多新的原生標準 API 出現。使得原先為解決功能不足而產生的 js lib,突然間許多 API 都有原生版本。也因此開始有人提倡使用新的 Javascript 標準 API 來寫作 js 。

其實,要求已經使用這些 js lib 的人改回用原生 API 的作法,就算新寫的程式可以,舊版的及早期開發完成的系統,也很難逐一修改。這之中比較適當的作法,應該是在新版 js lib 中,把原生 API 包進去,把那些不適宜的部分,予以註記不再使用 (deprecated),這樣應該會比較好。

Vanilla JS 很有趣,把需要的功能全部選一選,結果下載的vanilla.js,檔案大小為「零」。意思就是,直接用 browser 提供的 javascript 即可,也就是用標準的 javascript API 就對了。

Learning JavaScript Design Patterns 筆記 3

Publish/Subscribe Implementations

pubsubz/pubsubz.js

key point:
publish(topic, args): 執行特定topic的所有subscriber的func,並將參數args傳入
subscribe(topic, func): 將特定topic跟func綁定,以便publish中使用
unsubscribe: 移除 subscriber

Usage:
// 要綁定的 func
var mlog = function (t, d) { console.log(t+ ": " + d);};
// 綁定 topic (inbox/newMessage) 跟 mlog
var subscription = pubsub.subscribe("messagee", mlog);
// publish !
pubsub.publish("message", "hello world!");
pubsub.publish("message", ["test", "a", "b", "c"]);

2016年7月11日 星期一

Windows 7 沒事自動開機的解決辦法

查看已設定喚醒電腦的裝置
powercfg /devicequery wake_armed

查看可程式喚醒電腦的裝置
powercfg /devicequery wake_programmable

1. powercfg -lastwake 查看是誰起動 windows.
2. 裝置管理員 -> 內容 -> 電源管理 -> 取消勾選「允許這個裝置喚醒電腦」
3. 控制台 -> 電源選項 -> 目前電源計劃 -> 變更計劃設定 -> 變更進階電源設定 -> 睡眠 -> 允許喚醒計時器 -> 停用

參考 Powercfg 命令列選項

2016年7月9日 星期六

Learning JavaScript Design Patterns 筆記 2

The Observer Pattern


GoF book, Design Patterns: Elements of Reusable Object-Oriented Software :
"One or more observers are interested in the state of a subject and register their interest with the subject by attaching themselves. When something changes in our subject that the observer may be interested in, a notify message is sent which calls the update method in each observer. When the observer is no longer interested in the subject's state, they can simply detach themselves."

--------------------------------------------------
function OL(){ this.ol = []; }
OL.prototype.add     = function(o) { return this.ol.push( o ); };
OL.prototype.remove  = function(i) { this.ol.splice( i, 1 ); };
OL.prototype.count   = function() { return this.ol.length; };
OL.prototype.get     = function(i) { if( i > -1 && i < this.ol.length ){ return this.ol[i]; } };
OL.prototype.indexOf = function(o) {
  for(var i; i < this.ol.length; i++) { 
    if( this.ol[i] === o ) { return i; } 
    return -1; 
  }
};

// Maybe just extend OL class or using [] as new OL() ?
function Subject() { this.os = new OL();}
Subject.prototype.addObserver    = function( o ){ this.os.add( o ); };
Subject.prototype.removeObserver = function( o ){ this.os.remove( this.os.indexOf(o) ); };
Subject.prototype.notify         = function( context ){
  var observerCount = this.os.count();
  for(var i=0; i < observerCount; i++){
    this.os.get(i).update( context );
  }
};

// The Observer
function Observer(){
  this.update = function(){
    // ...
  };
}

--------------------------------------------------
// Extend an object with an extension
function extend(obj, extension){
  for (var key in extension){
    obj[key] = extension[key];
  }
}

// Concrete Subject
// Extend the controlling checkbox with the Subject class
extend( aSubject, new Subject() );

// aFunction will trigger notifications and passing data to its observers
aSubject.aFunction = function(){ aSubject.notify( aSubject.data ); };

// aObjAction will add observer to aSubject
aObjAction.aMethod = addO;
 
// Concrete Observer
function addO(){
  // Extend the aO with the Observer class
  extend(aO, new Observer());
 
  // Override with custom update behaviour
  aO.update = function( value ){ alert(value); };
 
  // Add observer to aSubject
  aSubject.addObserver(aO);
}

--------------------------------------------------
// When aObjAction.aMethod is called, aO observer is added to aSubject
// When aSubject.aFunction is called, aO will alert its data

Differences Between The Observer And Publish/Subscribe Pattern

Observer pattern: observer must subscribe itself to the subject firing the event.
Publish/Subscribe pattern: use a topic/event channel, subscriber received notifications and publisher firing the event.

2016年7月7日 星期四

在右鍵選單加上鎖定目錄,防止檔案刪除修改

有些檔案,像早期專案文件資料,個人記錄,或是圖片影音檔等。我們不希望不小心修改或刪除,此時可利用 Windows icacls 設定檔案或目錄的 DACLs 成唯讀,不可刪除,也不可修改。在命令模式下指令,就可以「鎖定」C:\TEMP\A 這個目錄。

icacls C:\TEMP\A /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T

要取回異動的指命如下

icacls C:\TEMP\A /remove:d administrators /T

當然也可以利用右鍵選單->內容->安全性->逐一設定權限,但不論是對指令,或是用滑鼠點選,太複雜也太繁鎖了,所以,我們就藉由 reg 檔來把上述的指令包進去,在右鍵選項上,建立兩個新的項目 Lock Folder 及 UnlockFolder。


LockFolder.reg

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\lockfolder]
@="Lock Folder"

[HKEY_CLASSES_ROOT\Directory\shell\lockfolder\command]
@="icacls %1 /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T"

UnlockFolder.reg

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\unlockfolder]
@="Unlock Folder"

[HKEY_CLASSES_ROOT\Directory\shell\unlockfolder\command]
@="icacls %1 /remove:d administrators /T"

檔案可由 Github 直接下載。直接註冊這兩個 reg 檔,就可以使用了。

1. 在目錄 A 的右鍵選單點 Lock Folder
 

2. 測試檔案,果然不能刪除。
 

3. 用 icacls 查看檔案及目錄的 DACLs


4. 紅色框就是 Lock Folder 加入的設定


5.Unlock Folder 解除鎖定
 

6. 再檢查檔案及目錄的 DACLs,可以發現,已經沒有剛加入的設定了。


7. 此時就可以正常刪除檔案及目錄。
 

這裡用到的 icacls 指令說明如下
LockFolder:
icacls %1 /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T

/deny: Explicitly denies administrators access rights
(OI): object inherit
(CI): container inherit
DE: delete
DC: delete child
WD: write data/add file
AD: append data/add subdirectory
/T: all specified files in the current directory and its subdirectories.

Unlock Folder:
icacls %1 /remove:d administrators /T
/remove:d removes all occurrences of denied rights to administrators
/T: all specified files in the current directory and its subdirectories.

注意:
此處用 administrators 這個 ID 作 DACLs 設定的對象,如果系統有作過不同的 ID 權限,則必需另外指定合適的 ID ,可將兩個檔案中的 administrators  修改成新的 ID。

Add Lock Folder on context menu

Sometime we don't want to modify or delete "history" file accidentally. How can we do ? Simple, by using icacls we can set different DACLs for files even directories. But if we only need to lock one directory and all its files, we can use following command to "lock" C:\TEMP\A directory.

icacls C:\TEMP\A /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T

If we want to "unlock" C:\TEMP\A directory. Use the following command

icacls C:\TEMP\A /remove:d administrators /T

It will be much useful if we add these two command as context menu items and simply use mouse right click to select one command on selected folder.


LockFolder.reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\lockfolder]
@="Lock Folder"

[HKEY_CLASSES_ROOT\Directory\shell\lockfolder\command]
@="icacls %1 /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T"

UnlockFolder.reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\unlockfolder]
@="Unlock Folder"

[HKEY_CLASSES_ROOT\Directory\shell\unlockfolder\command]
@="icacls %1 /remove:d administrators /T"


Download the two reg files on Github

Add these two reg. and than we have two addition items on context menu.

1. Click on A folder and right click to select Lock Folder.

  

2. Open command prompt and try to delete file or folder.
 

3.Use icacls to check file and folder's DACLs.


4. The red block is what Lock Folder added.

 

 5. Unlock Folder.


6.  Check file DACLs again.


7. Delete files and folder. This time we can successfully delete them.
 

In case you want to know what exactly these command means.

LockFolder:
icacls %1 /deny administrators:(OI)(CI)(DE,DC,WD,AD) /T
/deny: Explicitly denies administrators access rights
(OI): object inherit
(CI): container inherit
DE: delete
DC: delete child
WD: write data/add file
AD: append data/add subdirectory
/T: all specified files in the current directory and its subdirectories.

Unlock Folder:
icacls %1 /remove:d administrators /T
/remove:d removes all occurrences of denied rights to administrators
/T: all specified files in the current directory and its subdirectories.


Note:
We use "administrators " as the SID. If you want to use other ID, you need to modify the reg files, replace "administrators" and check if it working correctly.

為什麼寫程式跟作管理很難一人兼職?

這跟工作的特性有關

寫程式是一個非常注重專注力的工作,往往寫一個程式段落要花數小時,甚至到半天一天都有。

作管理是一個非常鎖碎的工作,這個問題解決了,下一刻又來新問題,每個問題都有不同處理方式,有時需找尋許多不同的資訊,並且不定時要跟團隊成員溝通。

這兩者對特性如此不同,長期下來,是很難由一個人承擔的。

2016年7月4日 星期一

Javascript OOP 最佳實作

OOP In JavaScript: What You NEED to Know

本文作者將 javascript OOP 的最佳實作寫成例子,日後寫程式時,可以參考
將 property 宣告在 function 中,將 method 宣告在 function.prototype 中


此外用 Google best javascript inheritance 還有許多文章。

3 ways to define a JavaScript class
不使用的方式
1.將 method 獨立宣告,然後 在 function 中引用,這會造成 gobal 中有許多 method。
2.在 function 宣告 method,這會造成每一次 new 就再產生該 method 。

建議方式,將 method 用 function.prototype 方式宣告,這樣只保有一個 method。而 property 宣告在 function ,這樣就每 new 一個 function ,就產生新的 property 實例。

如何當好經理? --- 值得記錄下來

如何當好經理? 中文翻譯
A Manager’s FAQ 英文原文

如何讓員工表現更好?告訴他們幹得不錯。
如何才能給予負面回饋?顯示你的好奇心。
如何決定授權內容?把你想做的事情授權給別人。
如何確定優先次序?先解決問題。然後預防問題。
如何給員工評級?不要。教他們自評。
什麼時候該炒人?當你知道他們不能成功的時候。
如何炒人?通過為我們的失敗道歉。
為什麼不能告訴大家應該做什麼?因為你的責任越大,你的權威就越小。
如何知道自己是不是好經理?員工找你徵求建議。
如何知道我是不是有一支好的管理團隊?問題向上傳遞。

詳細內容參考連結內文。

2016年7月3日 星期日

Learning JavaScript Design Patterns 筆記

Learning JavaScript Design Patterns 說明許多javascript模式,在此作些筆記。

由於Javascript是個有「洞」的語言,因此試圖去理解別人寫的javascript程式碼,無疑是給自己找麻煩,而自己寫javascript若沒有採用好的模式,將來作維護時,也很容易就發生看不懂的狀況。因此,寫 javascript 之前,先了解可用的模式,是「初學者」必需要作的第一步。當然,直接看模式對初學者來說,會比較辛苦些,但至少看過一遍後,寫的程式比較有機會將來可以維護。以前作大型專案時,若前端用很多javascript,在作程式改版或維護時,至少80%就是打掉重寫! 跟 Java 比,javascript困難太多了。

由於該書的程式碼用長名稱,使得模式的「樣子」不易一眼看出來,所以將此書中的模式,用較短命名重寫,重點是方便一眼看出模式的樣子,實際命名時還是要注意使用常用的命名方式。


What is a Pattern? 什麼是模式
  • Patterns are proven solutions 模式已驗證可提供解決方案
  • Patterns can be easily reused 模式易於理解
  • Patterns can be expressive 模式易於表達

The Constructor Pattern

// 1. Object Creation
var a = {};
var a = Object.create( Object.prototype );
var a = new Object();  

// Object keys and values
// 2.1 dot
a.k = "v";
var value = a.k;

// 2.2 Square bracket
a["k"] = "v";
var value = a["k"];

// 2.3 Object.defineProperty
Object.defineProperty( a, "k", {
    value: "v",
    writable: true,
    enumerable: true,
    configurable: true
});

// 2.4 Object.defineProperties
Object.defineProperties( a, {
  "k": { value: "v", writable: true },
  "l": { value: "w", writable: false}
});

// 3 Basic Constructors
function A(i, j) {
  this.i = i;
  this.j = j;
  this.total = function () { return this.i + this.j; };
  this.max   = function () { return Math.Max(this.i, this.j); };
}

// 4 Constructors With Prototypes
function A(i, j) {
  this.i = i;
  this.j = j;
}
A.prototype.total = function () { return this.i + this.j; };
A.prototype.max   = function () { return Math.Max(this.i, this.j); };


The Module Pattern

// Object Literals
var a = {
    k: "v",
    f: function () { return k; }
};

// The Module Pattern
var a = (function () {
  var k = "v";
  function up() { k = k.toUpperCase(); }
  return {
    publicK: "value",
    getK:   function () { return k; },
    setK:   function (value) { k = value; },
    getUpK: function () { up(); return k; }
  };
})();

// Import mixins
var a = (function (b, c) {
  var k = "v";
  function up() { k = k.toUpperCase() + b + c; }
  return {
    publicK: "value",
    getKBC: function () { return k + b + c; },
    setK:   function (value) { k = value; },
    getUpK: function () { up(); return k; },
  };
})(b ,c);

// Exports
var a = (function () {
  var b = {};

  var k = "v";
  function up() { k = k.toUpperCase(); }

  b.publicK = "value";
  b.getK    = function () { return k; };
  b.setK    = function (value) { k = value; };
  b.getUpK  = function () { up(); return k; }

  return b;
})();


The Singleton Pattern

var singleton = (function () {
  var instance;

  function init() {
    var k = "v";
    function privateM(){ /* ... */ }
    return {
      publicK: "public",
      publicM: function () { privateM(); }
    };
  };
 
  return {
    getInstance: function () {
      if ( !instance ) { instance = init(); }
      return instance;
    }
  };
 
})();

2016年6月22日 星期三

開發 File Monitor 2

之前完成的程式,用 Class Diagram 隨便畫一下,大概的關係圖如下:

由於 WatchDir 中,為了使用 textArea 來顯示訊息,所以把 textArea 當作參數傳給 WatchDir。此外,textArea 使用String.format處理產生的訊息。

這樣的寫法,其實變成日後要加新的「訊息處理者」,如 MessageDialog 來產生 alert 對話視窗時,變成要再加參數傳給 WatchDir。而且使用的 ? 方法,也要另外再寫 String.format 來處理對應的訊息。因此這部分需要作修改,重構一下。


讓 WatchDir extends Observable,把所觀測到的檔案訊息,包成一個 final 物件FileMonitorEvent,將訊息資料傳入個別的 Observer 作處理。作成 final 物件,是因為檔案異動訊息一產生,就不能被更改。圖中的 Observer (藍色部分),不一定需要實際的 class ,也可以用 lambda 或 anonymous 的方式。

此外,一個監控目錄,應該對到一個 OptionDialog,也就是之前提到的 UseCase 中,除了顯示檔案異動訊息之外,其它的動作設定,均會在這個 OptionDialog 中。而個別的 Observer 也會在這個 OptionDialog 實作。如此將來可以擴充成多個 OptionDialog ,就可以監控多個目錄。

再回頭看一下這兩個 Class Diagram,也許會有人認為,其實一開始是可以設計第二張圖的,為什麼不一開始就「設計好」呢?這個部分要思考一下幾個想法。

首先,每個人寫程式的方式其實是不一樣的,即使是同一人,每次作法也不見得會一樣。以這個監控檔案異動的程式,當初在寫的時候,「重點」是趕快寫出來,讓監控檔案異動的部分可以動再說,如果實際上 Java API 作不到,可能要採用其它的語言來寫。

第二,因為不了解實際 Java API 處理檔案監控的機制為何,所以一開始也無法很快了解要用到 Observer pattern 來處理「檔案異動訊息」,而原本的範例程式,就 for 一直跑,要修改成 Thread 來使用。再加上之前寫的都是 Server Side 的 Java, Swing 很久沒寫了,WindowBuilder 也才剛用個「幾天」,雖然很直覺,很好用,但總是要花時間摸索。如果不先把功能作出來,大概時間都會花在處理了解這些 Swing 元件 或 找 pattern 了。

第三,這其實是個小程式,因此初期不需要太多的設計,就可以很快實作出來,而會卡關的,除了對 API 不熟之外,還有環境的不了解,因此,當初寫的時候,「一不小心」就花了半天的時間去查「所有可以監控檔案」的程式寫作,包含 windows 的 API 等,最後才發現,就用 Java 自己的 API 就可以了。這樣寫程式,很容易「發散」沒有專注。

上述的想法,在寫作小程式或試驗的時候,是可以這樣處理的。大型專案就比較難這樣作。因為大型專案如果沒有作好設計,一開發下去,若有問題,人力物力還要重新投資。

從想到作,寫大概的 UseCase,程式實作出來,作 Class Diagram,然後再改成新版用 Observer pattern 也花了二天左右。真的作不對,整個打掉再來,也還能接受。

倒是寫這個 blog 文章花的時間比較多。因此,有一個構想點子,會比去了解更多有的沒有的技術,會更重要。因為這樣比較好聚焦在要處理的程式碼上。而技術的使用,在需求及功能初步達成後,再回頭重構也是可以的。

2016年6月19日 星期日

開發 File Monitor

加密勒索病毒 CryptoLocker 是很難對付的病毒,中毒之後,重要的檔案都會被加密,而解密的 key 在對方手上,除非防毒軟體有找到這些 key ,不然除了付錢給對方,要求提供解密功能,用其它的方式,幾乎是不可能回復檔案。

但加密檔案,一定會動檔案作異動。這個時候若有可以監控指定目錄下的檔案異動程式,就可以得知是否有可疑的異動。以便使用者進一步作處理。

因此 File Monitor 這個程式,就是因應這樣的需求而作的。

本程式是用 Java 語言,在 Eclipse 下寫作而成。

1. 首先是大概確認使用案例,這裡用簡單的 UML Use case 表示

使用者可以有三個動作,一是執行或停止監控,一是設定指定監控目錄,最後則是設定選項,可以指定目錄、指定檔名過瀘、顯示訊息、撥放聲音檔、執行程式等。先實作紅色框的部分。

2.使用 Eclipse ,建立 FileMonitor 專案,並用 WindowBuilder 拉出如下的視窗

畫面分成三個部分,
    上方 panel,放 Monitor Directory: 文字和按鈕等元件
    中間 scrollPane,放顯示監控到的檔案異動 textArea
    下方 textPane,顯示訊息

3. 實作檔案監控的部分,需要使用到 WatchService API ,可參考 Watching a Directory for Changes ,使用它所提供 WatchDir example,原程式是命令模式執行,並用 System.out 輸出訊息,因此要修改為接收一個 textArea 作輸出。此外,把 WatchDir 實作 Runnable 界面,這樣就可以用 Thread 起動。因此也需加上 run() 的實作部分。


4.在 UI 使用 WatchDir,主要增加 button 的動作。

btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    try {
      wd = new WatchDir(Paths.get(textField.getText()), true, textArea);
      Thread t = new Thread(wd);
      t.setDaemon(true); 
      t.start();
      btnStart.setEnabled(false);
      btnStop.setEnabled(true);
    } catch (IOException e1) {
      textPane.setText(e1.getMessage());
    }
  }
});
panel.add(btnStart);

btnStop = new JButton("Stop");
btnStop.setEnabled(false);
btnStop.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    wd.stopRunning();
    btnStart.setEnabled(true);
    btnStop.setEnabled(false);
  }
});
panel.add(btnStop);

btnClear = new JButton("Clear");
btnClear.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    textArea.setText("");
  }
});
panel.add(btnClear);

5. 實際的執行結果如下

寫程式「前」,先寫測試

1.程式是給其它的人用的,所以先寫測試,就是要讓自己先了解這程式「如何」使用。反過來說,如果測試很難寫,代表程式可能不好用,看是要修改規格,或是修改界面等。

2.先寫測試可以提昇程式開發人員「預見」程式的外部運作方式,有助於精進程式設計能力。

3.只有一類人可不寫測試,那就是設計天才,一出手就很完整,就不需測試。但這類人畢竟是少數,而若是團隊開發,再天才,程式還是得讓其它人使用,還是需要提供測試,這樣別人才知道天才的程式怎麼使用。

4.有時測試不見得是寫程式,也可以先作測試設計,了解到底要作的是什麼。

2016年6月18日 星期六

開發 Firefox webextensions addon

Firefox 從 47 之後,採用了 webextensions API,以前一直使用的 XUL 等就廢除無法使用,使得不少依存在 XUL 的 addon 通通不能用了。而 webextensions 要到 48 版才會有穩定版本,也就是該有的 API 實作會出來。

目前使用的是 46.01 ,裡面已經有部分可以使用的 webextensions 。故記錄一下設定開發環境的過程,以便下次回頭查詢。

1.首先,建立另一個 Profile,執行 firefox.exe -P 新增 dev。然後就可以用 firefox.exe -no-remote -P dev 當作開發環境。
2.安裝 DevPrefs 把開發環境設定好,這樣就不用一個一個設定了
3.Options -> Advanced -> Update 設定永不檢查更新,尤其是在用舊版程式作開發時,一不小時,Firefox 就更新了。
4.在網址列輸入 about:debugging 用 Load Temporary Add-on 把 manifest.json 載入 。
5.把 about:debugging 放入書籤中,並設定顯示書籤列。
6.因為每次修改,均要重啟 firefox,用 firefox.exe -no-remote -P dev 起動後,按 about:debugging,按 Load ... Addon,再按 Ctrl+Alt+Shift+I 開啟 Browser Toolbox 的除錯工具。就可以測試 addon 了。

至於 addon 的寫作,可參考 Your first WebExtension ,裡面也有範本,但要注意,有些範本使用到的 API 要到 48 版才有,若是用比 48 還早的版本,不是每一個都能正常運作。

2016年6月17日 星期五

研究 Scala 的一小部分想法

這幾天開始研究 Scala ,相較於 Javascript ,嚴謹多了,而它主要是基於 JVM 的下一代 Java 語言。其中有不少語法特性,值得思考。

比方像是 override 關鍵字,若子類別使用到父類別同名的成員變數或功能,則必需指定 override ,表示子類別「確實」要使用同名的變數或功能,而且要自己實作這個功能。這樣的語法,使得軟體工程師在寫程式,一定會注意到是否寫到 override 的部分。

以前作大型專案時,曾經有個網頁程式一直出錯,但很難查出問題在那。後來就從頭一步一步查起,結果是在前端的 javascript 中,有一個功能的名字,跟使用到的 javascript lib 「一模一樣」,但因為 javascript 沒有「強制」override 的識別功能,所以,程式跑起來就不穩定,只要使用到這個同名功能時,就會出錯。

另一個看到的是 Structural typing。這個跟 Groovy 的 duck 的概念類似,也就是,如果走起來像個鴨子,叫聲像個鴨子。那它就應該是個鴨子。Scala 的 Structural typing,可以自行定義一個結構,來表示這些行為,從而使用這些動作,即使是沒有關係的類別,只要符合結構定義的行為,就可以使用這個行為。

def doQuack(o: {def quack(value: String): String}) {
  println (o.quack("Quack"))
}
class NorthDuck {
  def quack = "quack"
}
class SouthDuck {
  def quack = "quack quack"
}
doQuack(NorthDuck)
doQuack(SouthDuck)

這樣的特性,有什麼用處?有時候,我們需要增加既有的程式一些功能,但原程式並沒有提出 interface 之類的元件,可以讓我們用繼承的方式使用時,就可以藉由結構,把需要的「行為」定義出來,這樣就可以增加新的類別元件,採用跟原程式庫中相同的「行為」名稱,而不需動到既有的程式庫。

2016年6月16日 星期四

Javascript是個有「洞」的語言

直到 ECMAScript 2015 出來之前,Javascript 一直是個有洞的語言,它很容易讓程式出錯,讓開發人員看不懂程式碼的用意,尤其是一些「所謂」的技巧

5 nifty JavaScript tricks that you may not know

比方像第一個 case
if(fruit === 'apple' || fruit === 'banana' || fruit === 'chikoo'){
    doMagic();
}

改寫成底下
if({apple:1,banana:1,chikoo:1}[fruit]){
    doMagic();
}
這樣作的目的是讓原來的文字檢查,變成用一個 {} 物件的 key / value 檢查,但這種寫法,其它的語言不一定能直接實作,尤其是現在是跨語言使用的時代,愈多特定語法的使用,愈不能在別的語言運用。同時,這種技巧也愈需要花時間了解。

寫程式,是要解決問題,而不是解決程式的問題。

由於 Web 前端都採用 javascript 處理,故使用這個語言,最佳的策略便是使用「高手們」作出的套件,愈高階愈好,像JQuery比較低階。而AngularJS 就比較高階。因為採用高階套件,就不需寫太多javascript程式碼,就可以避免出錯。Google 有 GWT,可以用 Java 寫 javascript ,可惜它的 Designer 及似乎停止發展,更新緩慢。這可能是因為後起之秀 Vaadin 有開發付費版本的 Designer ,要避免競爭之故吧。

但現在的程式開發,重點不是開發,因為現今能用的技術,幾乎都能很快速實作出需要的功能,而只有好的點子的實作,才會有最多人使用。因此,如果構思好點子,會比使用這些炫麗的功能更為重要。

2016年6月15日 星期三

Eclipse Java Swing BeansBinding JSR 295

UI 元件常需跟 Model 的資料作連動,除了自己寫程式之外,也可以用 Eclipse WindowBuilder + BeansBinding 提供的方式作連動。

底下是簡單的範例,當使用者輸入最上方的文字方塊,最下方會同步顯示輸入的文字。按下 Add 後,該文字就會置入中央的列表中,並清空文字方塊。

 


1.首先要加裝  jsr 295 Beans Binding 的實作,選用的是 BetterBeansBinding ,如果使用 Gradle,則要設定 BetterBeansBinding SwingBinding


2.執行 gradlew.bat 把 jar 檔設定好後,隨便拉一下 Swing 組成如下的視窗,可以看到有個Bindings的tab
 

3. 把 Target 跟 Model 的 text 綁定起來。
 

4.底下是自動產生的程式碼片斷,怎麼解讀?算了,不重要,有興趣自己去看 JSR 295,只要它能讓兩個元件彼此資料連動就好了。
 

好啦,這樣就可以連動兩個元件的資料了。

不過 JSR 295 好像熄火了,沒什麼動作,所以這些程式庫也很久沒有新版。目前比較「熱」的是 JGoodies Binding ,至於怎麼用,下次再研究吧 ......

2016年6月13日 星期一

Eclipse WindowBuilder 的使用心得

Eclipse 預設在建立 Swing 物件時,會把一切組件宣告通通放在 constructor 中。

但有時要特別處理某組件,我們可以將它 expose 出來,也就是多一個 get method 並把該組件宣告成 class 成員變數,如果沒有外部程式使用 get method,那就刪除那個 get method。另外使用 private method 操作該組件。

例如:
1.底下是一個簡單的 Swing 程式
 

2.在 Eclipse 的程式碼如下,可見綠色框的部分,已經是成員變數,而紅色框的部分,則定義在method中
 

3. 回到 Desgin 模式,將 textArea Expose 出來
 

4.  切換到程式碼模式,就可以看到改變的部分
 

5. 此時就可以在整個 class 中,使用 textArea ,因為它已經是成員變數了

 

如果希望每一個組件都是成員變數,可以由 Window -> Preferences -> WindowBuilder -> Code Generation 中,設定 Field 模式即可
  

這樣產生出來的組件,都會是成員變數了。

分時分工專注

想要一段長時間的專注在單一事件上,有時不是容易的事,比如寫程式就是一例,此時可以採用分時分工專注的方法,也就是,當無法專注在寫程式時,就去作簡單的運動,專注在運動上,然後再回頭寫程式,或許會有進展。此外看其它文章,聽音樂,寫blog等等,都可以分時分工專注。當然重要的眼睛休息時刻也要加進去,這樣應該會比較有效率些。

至於不同的事件花多少時間,這個就看自己掌握了。

2016年6月12日 星期日

減少冗長的樣板程式碼 - Lombok

寫 Java 程式時,常會需要為成員變數建立 getter 及 setter,使用 IDE 工具可以容易自動建立這些樣板程式碼,但當成員變數過多時,整個程式碼就會變得很長,而真正運作的程式碼,就會淹沒在其中。有個 Lombok 的專案,針對這個部分,作了一系列的 annotations。效果顯示如下:

1.未使用前,右方只有一堆成員變數。
 

2.使用 @Data 後,自動產生樣板程式碼,顯示在右方 method 清單上,但左方並沒有產生這些程式碼,都被 @Data 代表了。


3.而底下就是真正執行功能的程式,整個程式碼清爽多了




專案主頁
https://projectlombok.org/
詳細說明
http://jnb.ociweb.com/jnb/jnbJan2010.html

2016年6月5日 星期日

軟體建構之道 (Code Complete, 2/e)

這幾天開始讀這部軟體工程巨作。目前只看到第五章,但其實很多觀念在專案中,不時會使用到。如果說沒有開發程式的經驗,就先看這本書,是不錯。但經過專案及程式開發後再來看,會更有啟發性。

2016年5月5日 星期四

前端網頁設計,慎用非同步模式

ajax 的資料處理,可以讓前端網頁異動最少,動在只需要動的地方,但同時也會有些問題,比如作資料刪除的動作時,若沒整頁回讀,當其中一筆資料「尚未刪除完成」而有錯誤出現時,若使用者「還同時作其它筆資料的刪除」,那此部分的處理機制就比較複雜。

ajax 資料處理,最好是「可重覆」性的動作,像是讀資料的部分,就可以使用,而需要進行「因資料處理發生錯誤」的部分,使用 ajax 就必需將多種例外處理也考量進去,避免使用者誤判或是沒收到及時的錯誤訊息。

2016年5月4日 星期三

領導者跟管理者不一定是同一人

就公司來說,董事長比較像領導者,總經理比較像是管理者。雖然如此,大多數情形是同兼兩者,比例上有差別,董事長專職領導,而各階層的管理人員,也會有部分領導功用

領導者無論何時,都要有方向

不然底下的人會「立刻」無所適從。

2016年5月2日 星期一

管理者的最重要工作,讓自己沒事作

管理者對組織對團隊負責,主要是內部團隊跟外部環境互動的重要角色。因此,若管理者卡在事物上,則一些意外的狀況,就無法有效處理。

2016年4月26日 星期二

小公司的企業文化

當公司人數只有 20 人以下時,要形成的文化是「家公司文化」,讓員工有歸屬感,有家的感覺,此時不宜採獎金,業務也不可以有,但業績好,公司可以發整體的獎金。

當公司達 50 人至 200 人,或是已有完成產品要推出時,要形成的是「積極的公司文化」,此時已有較大的部門分工,每個部門可以有自己的利潤中心,招募人員重點在衝剌。

當公司已上軌道,要形成的是「有能力者出頭」的公司文化,讓人才源源不絕,得以重用,這樣公司面臨各種狀況,都可以處理。

2016年4月18日 星期一

NetBeans 8.1 編輯器亂碼或行數亂碼

NetBeans 8.1 設定字型或在打開UTF-8編碼的檔時,若有亂碼(包含行數)可以下方式解決
C:\Program Files (x86)\NetBeans 8.1\etc\netbeans.conf
netbeans_default_options= 後面加 -J-Dfile.encoding=UTF-8
若覺得 UI 字太小,可以再加上  --fontsize 18  (預設11) 作調整