// Create and add second product: Blink/20420101
var engine = new UserAgent.Product('Blink', '20420101');
userAgent.addProduct(engine);
// EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101
userAgent.toString();
// Make some more changes to engine product
engine.setComment('Hello World');
// EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101 (Hello World)
userAgent.toString();
根據(jù)你的代碼的復(fù)雜度,你可能會在組織結(jié)構(gòu)上花費(fèi)一些時間。利用設(shè)計模式是組織你的代碼庫的好辦法,甚至可以解決一些技術(shù)問題。這還能避免加入新特性帶來的大面積重構(gòu)。
##靈活性和定制性
靈活性是讓代碼庫變得強(qiáng)大的要素,但是確定可以定制與不能定制的界限是很困難的。 chart.js 和 D3.js 是很好的例子。這兩個代碼庫都是用來進(jìn)行數(shù)據(jù)可視化的。Chart.js可以很簡單的創(chuàng)建不同形式的內(nèi)置圖表。但是如果你想對圖像進(jìn)行更多的掌控,D3.js才是你需要的。
有好幾種方法可以把控制權(quán)交給用戶:配置,暴露公共方法,通過回調(diào)和事件。
配置代碼庫通常在初始化之前完成。但是一些代碼庫允許尼在運(yùn)行時對配置進(jìn)行修改。配置通常被細(xì)小的部分限制,只有為了之后的使用而修改它們的數(shù)值才是被允許的。
// Configure at initialization
var userAgent = new UserAgent({
commentSeparator: ';'
});
// Run-time configuration using a public method
userAgent.setOption('commentSeparator', '-');
// Run-time configuration using a public property
userAgent.commentSeparator = '-';
方法通常是暴露給實例使用的,比如說從實例中獲取數(shù)據(jù),或者設(shè)置實例的數(shù)據(jù)和執(zhí)行操作。
var userAgent = new UserAgent;
// A getter to retrieve comments from all products
userAgent.getComments();
// An action to shuffle the order of all products
userAgent.shuffleProducts();
回調(diào)通常是在公共的方法中被傳遞的,通常在異步操作后執(zhí)行用戶的代碼。
var userAgent = new UserAgent;
userAgent.doAsyncThing(function asyncThingDone() {
// Run code after async thing is done
});
事件有很多種可能。有點像回調(diào),除了增加事件句柄是不應(yīng)該觸發(fā)操作的。事件通常用于監(jiān)聽,你可能會猜到,這可是事件!更像回調(diào)的是,你可以提供更多的信息和返回一個數(shù)值給代碼庫去進(jìn)行操作。
var userAgent = new UserAgent;
// Validate a product on addition
userAgent.on('product.add', function onProductAdd(e, product) {
var shouldAddProduct = product.toString().length < 5;
// Tell the library to add the product or not
return shouldAddProduct;
});
在一些例子中,你可能允許用戶對你的代碼庫進(jìn)行擴(kuò)展。因此,你需要暴露一些公共方法或者屬性來讓用戶填充,像Angular的模塊 ( angular.module('myModule'))和Jquery的 fn ( jQuery.fn.myPlugin )或者什么都不做,只是簡單的讓用戶獲取你的代碼庫的命名空間:
// AngryUserAgent module
// Has access to UserAgent namespace
(function AngryUserAgent(UserAgent) {
// Create new method .toAngryString()
UserAgent.prototype.toAngryString = function() {
return this.toString().toUpperCase();
};
})(UserAgent);
// Application code
var userAgent = new UserAgent;
// ...
// EVILCORPBROWSER/1.2 (X11; LINUX; EN-US) BLINK/20420101
userAgent.toAngryString();
類似的,這允許你重寫方法。
// AngryUserAgent module
(function AngryUserAgent(UserAgent) {
// Store old .toString() method for later use
var _toString = UserAgent.prototype.toString;
// Overwrite .toString()
UserAgent.prototype.toString = function() {
return _toString.call(this).toUpperCase();
};
})(UserAgent);
var userAgent = new UserAgent;
// ...
// EVILCORPBROWSER/1.2 (X11; LINUX; EN-US) BLINK/20420101
userAgent.toString();
在后面的例子中,允許你的用戶獲取代碼庫的命名空間,讓你在對擴(kuò)展和插件的定義方面上的控制變小了。為了讓插件遵循一些約定,你可以(或者是應(yīng)該)寫下文檔。
##測試
對測試驅(qū)動開發(fā) (test-driven development) 來說,寫下大綱是良好的開始。簡單來說,指的是在你寫實際的代碼庫之前,在你寫下測試準(zhǔn)則的時候。如果測試檢查的是你的代碼特性是否跟期待的一樣,以及你在寫代碼庫之前寫測試,這就是行為驅(qū)動開發(fā)。不管怎樣,如果你的測試覆蓋了你的代碼庫的每一個特性,而且你的代碼通過了所有的測試。你可以確定你的代碼是可以正常工作的。