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