JavaScript Design Pattern - Singleton Pattern
Có thể bạn đã nghe quen về Singleton. Singleton Pattern giới hạn số lượng instance của một class là một . Trong JavaScript, bạn có thể triển khai Singleton Pattern theo cách sau. Singleton Pattern cơ bản var mySingleton = ( function ( ) { var instance ; function init ( ) ...
Có thể bạn đã nghe quen về Singleton. Singleton Pattern giới hạn số lượng instance của một class là một. Trong JavaScript, bạn có thể triển khai Singleton Pattern theo cách sau.
Singleton Pattern cơ bản
var mySingleton = (function() { var instance; function init() { var number = 0; return { setNumber : function(x) { number = x; }, getNumber : function() { return number; } }; } return { getInstance : function() { if (!instance) instance = init(); return instance; } } })(); var instA = mySingleton.getInstance(); console.log("instance A: ", instA.getNumber()); // instance A: 0 instA.setNumber(10); console.log("instance A: ", instA.getNumber()); // instance A: 10 var instB = mySingleton.getInstance(); console.log("instance B: ", instB.getNumber()); // instance B: 10 console.log(instA === instB); // true
Giải thích
Các bạn có thể thấy, cách triển khai Singleton trên rất giống với Module Pattern. Chỉ có một chú ý là, mySingleton chỉ có một access point duy nhất là getInstance. Vậy tại sao khi sử dụng function này thì ta chỉ thu được một instance duy nhất?
Đúng vậy, ban đầu khi chưa gọi getInstance lần nào thì biến instance sẽ là undefined. Lúc này, instance sẽ được khởi tạo bằng cách sử dụng hàm số init. Cuối cùng, hàm số trả về biến instance. Đối với các lần gọi getInstance tiếp theo, vì instance đã khác undefined nên nó sẽ không được tạo mới mà sẽ return ngay lập tức.
Như ví dụ trên, instA khi mới tạo ra thì getNumber sẽ trả về 0. Trong khi, instB khi mới tạo ra thì getNumber trả về 10 - giá trị này được set ở instA trước đó. Và quan trọng hơn, instA === instB trả về giá trị true. Như vậy, thực chất instB cũng chính là instA.
Singleton with a cached static property
function User() { // do we have an existing instance? if (typeof User.instance === 'object') { return User.instance; } // proceed as normal this.firstName = 'John'; this.lastName = 'Doe'; // cache User.instance = this; // implicit return // return this; } // Usage: var curUser = new User(); console.log(curUser.firstName, curUser.lastName); // John Doe var other = new User(); console.log(other.firstName, other.lastName); // John Doe console.log(other === curUser); // true
Cách này khi mới đọc thì sẽ thấy hơi ảo, ở chỗ là, trong hàm User ta lại sử dụng User.instance. Nhưng nếu nhìn theo khía cạnh, function cũng chính là một object thì mọi chuyện sẽ trở nên đơn giản.
Như trong ví dụ trên, khi khởi tạo curUser (lần đầu tiên), User.instance đang có giá trị là undefined, nên mọi thứ được xử lý như bình thường. Khi kết thúc hàm, ta gán User.instance = this hay nói cách khác là User.instance = curUser. Đến khi khởi tạo đối tượng thứ hai là other, lúc này User.instance đã là curUser - một object, nên hàm trên sẽ return về User.instance (curUser). Đó, dù có gọi hàm khởi tạo bao nhiêu lần thì ta cũng chỉ thu được một đối tượng duy nhất.
Tham khảo
- Learning JavaScript Design Patterns
- JavaScript Design Pattern Singleton
Theo dõi Lam Pham trên Viblo để nhận thông báo khi có bài viết mới nhất:
- Facebook Fanpage: Complete JavaScript
- Facebook Group: Hỏi đáp JavaScript VN