Thứ sáu, 19/04/2019 | 00:00 GMT+7

Làm việc với Singletons trong JavaScript


Singleton là một trong những mẫu thiết kế nổi tiếng và bị ghét nhất trong số các nhà phát triển. Rất dễ dàng để triển khai một version cơ bản của mẫu singleton (có thể là lý do tại sao nó bị lạm dụng quá nhiều). Trong bài viết này, ta sẽ xem xét các singlet là gì và cách triển khai chúng tốt nhất trong JavaScript.

Đôi khi bạn chỉ cần có một thể hiện của một lớp và không cần nhiều hơn nữa. Nó có thể là một loại trình quản lý tài nguyên nào đó, một loại duy trì các cổng I / O của ứng dụng của bạn hoặc một số tra cứu global cho các giá trị. Đó là nơi những người độc thân đi vào.

Singleton được sử dụng để tạo một thể hiện của một lớp nếu nó không tồn tại hoặc trả về tham chiếu của lớp hiện có. Nói cách khác, các Singleton được tạo chính xác một lần trong thời gian chạy của ứng dụng trong phạm vi toàn cục.

Bạn có thể hỏi, tại sao lại sử dụng các lệnh đơn trong một ngôn ngữ có các biến toàn cục? Chúng có vẻ không khác nhiều so với các biến toàn cục (hoặc biến tĩnh) và hầu hết coi chúng là "các khối cầu được tôn vinh". JavaScript nói riêng có sự khác biệt đó rất mờ nhạt, bởi vì đoạn mã sau…

var Alliagator = {
  color: "green", 
  getColor: function() { 
    console.log(color);
  };
}

Về mặt kỹ thuật là một đối tượng singleton, vì nó là một đối tượng theo nghĩa đen - nghĩa là đối tượng có tên đó là duy nhất trong toàn bộ ứng dụng (vì nó không thể khai báo lại).

Điều này dường như cũng có nhiều điểm chung với các biến toàn cục trong JavaScript. Vậy sự khác biệt là gì?

  • Đối với người mới bắt đầu, các biến toàn cục có phạm vi từ vựng trong khi các biến đơn thì không, nghĩa là nếu có một biến khác có cùng tên với biến toàn cục bên trong một khối lập trình, thì tham chiếu đó được ưu tiên; Trong trường hợp các singleton, là loại tĩnh trong khai báo, không nên khai báo lại tham chiếu đó.
  • Giá trị của một singleton được sửa đổi thông qua các phương thức.
  • Singleton không được giải phóng cho đến khi kết thúc chương trình, điều này có thể không đúng với một biến toàn cục.

Một ưu điểm thú vị của singleton là nó an toàn theo stream . Mặc dù tính năng đó không thực sự áp dụng cho Javascript, nhưng điều này rất hữu ích trong các ngôn ngữ như C ++. Đây chỉ là một trường hợp để chứng minh quan điểm rằng không thực sự kỳ lạ khi sử dụng các singlelet ngay cả trong một ngôn ngữ hỗ trợ các biến toàn cục.

Có những tình huống mà các singlet rất tiện dụng. Một số ứng dụng của singleton là các đối tượng ghi log hoặc các lớp cài đặt cấu hình.

Một cách nhanh chóng để khai báo một singleton sẽ là:

// Declare them like this
var SingletonInstance = { 
 method1: function () { ... }
 method2: function () { ... } 
};

// and use them as such
console.log(SingletonInstance.method1());
console.log(SingletonInstance.method2());

Mặc dù đây có thể là cách dễ dàng, nhưng nó không nhất thiết là tốt nhất. Một cách khác là sử dụng các lớp nhà máy cho phép ta tạo một singleton một lần.

var SingletonFactory = (function(){
  function SingletonClass() {
    // ...
  }
  var instance;
  return {
    getInstance: function(){
      // check if instance is available
      if (!instance) {
        instance = new SingletonClass();
        delete instance.constructor; // or set it to null
      }
      return instance;
    }
  };
})();

Điều này tốt hơn ví dụ trước vì định nghĩa lớp là private và phương thức khởi tạo bị xóa sau khi tạo version đầu tiên, điều này giúp ta ngăn chặn các singleton trùng lặp trong chương trình. Nhưng cách tiếp cận trên trông rất giống với mô hình nhà máy.

Có lẽ cách tiếp cận rõ ràng nhất là sử dụng kết hợp các lớp ES6, constObject.freeze() :

class Singleton {
  constructor(){
   ...
  }

  method1(){
    ...
  }

  method2(){
    ...
  }
}

const singletonInstance = new Singleton();
Object.freeze(singletonInstance);

Ta có thể đi xa hơn một chút và viết singleton này trong một module và sau đó xuất nó với chức năng xuất ES6 .

export default singletonInstance;

Sau đó, sử dụng singleton đó bằng lệnh nó:

import mySingleton from './path-to-my-singleton-definition.js'; 
mySingleton.method_1() // Now use your singletons

Vì vậy, hãy lựa chọn, tìm cách tiếp cận nào phù hợp nhất với ứng dụng của bạn và đặt tính dễ đọc lên hàng đầu.

Kết luận

Rất có thể bạn sẽ gặp phải tài liệu trực tuyến tràn ngập về cách các singlet có hại cho các thiết kế hướng đối tượng. Ý tưởng là sử dụng các singleton nơi nó không ảnh hưởng đến trạng thái của ứng dụng, bởi vì nếu bạn không tuân theo, thì việc kiểm tra sẽ diễn ra ngay ngoài cửa sổ. Điều này hạn chế nghiêm trọng việc sử dụng chúng trong các ứng dụng lớn. Hầu hết các nhà phát triển đồng ý rằng trạng thái global là xấu, nhưng họ quá yêu thích chúng để nhìn vào những mặt xấu của nó trong khi những người khác lại cố gắng tránh sử dụng trạng thái global . Cho dù singleton là tốt hay xấu, hiểu được mẫu thiết kế cơ bản này và thêm nó vào bộ công cụ lập trình của bạn luôn là một ý tưởng khôn ngoan.

Đọc thêm

Hãy xem bài đăng trên blog này của Misko Hevery để biết thêm thông tin chi tiết về vấn đề nhà nước global với singletons.


Tags:

Các tin liên quan

Cách sử dụng Axios với JavaScript
2019-04-05
Giới thiệu về Lặp lại và Trình lặp trong JavaScript
2019-03-13
D3.js: Hiểu các lựa chọn và so sánh với Vanilla JavaScript
2019-03-04
Xem xét Phạm vi, Ngữ cảnh, Tham chiếu Đối tượng và Thuyết minh trong JavaScript
2019-02-25
Sử dụng JavaScript Mixins
2019-02-12
Đọc mã nguồn JavaScript, sử dụng AST
2019-02-09
JavaScript Biểu thức chính quy cho Người bình thường
2019-02-07
Mẫu kế thừa nguyên mẫu JavaScript
2019-02-01
Các mẫu hướng đối tượng JavaScript: Mẫu nhà máy
2019-01-23
Đối tượng, Nguyên mẫu và Lớp trong JavaScript
2019-01-10