Singletons được hiểu là các class có thể được khởi tạo một lần và có thể truy cập trên toàn cục (international). Các class này có thể chia sẽ các state trong toàn bộ app, thì Singletons là một thứ tuyệt vời để quản lý international state trong một app.
Ví dụ tôi sẽ xây dựng một class Counter có:
- a
getInstance
là phương thức trả về worth của của occasion - a
getCount
trả về worth hiện tại của biến counter - an
increment
methodology làm tăng worth của counter lên 1 - a
decrement
methodology làm giảm worth của counter xuống 1
let counter = 0;
class Counter {
getInstance() {
return this;
}
getCount() {
return counter;
}
increment() {
return ++counter;
}
decrement() {
return --counter;
}
}
Tuy nhiên class này không đáp ứng các yêu cầu cho một Singleton! Một Singleton chỉ có thể được khởi tạo một lần. Hiện tại, chúng ta có thể tạo nhiều phiên bản của class Counter
let counter = 0;
class Counter {
getInstance() {
return this;
}
getCount() {
return counter;
}
increment() {
return ++counter;
}
decrement() {
return --counter;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
console.log(counter1.getInstance() === counter2.getInstance()); // false
Bằng cách gọi methodology new
2 lần, tôi đặt obj tên counter1 và counter2. Worth được trả về bởi methodology getInstance
của counter1 và counter2, nhưng chúng trả về các tham chiếu: chúng không hoàn toàn bằng nhau!
Hãy đảm bảo rằng class Counter
chỉ có thể tạo một lần
Để đảm bảo rằng một occasion
có thể được tạo, đó là tạo một biến variable được gọi là occasion
. Trong constructor của class Counter
, tôi có thể set occasion
bằng một tham chiếu đến occasion
khi một occasion
mới được tạo.
let occasion;
let counter = 0;
class Counter {
constructor() {
if (occasion) {
throw new Error("You'll be able to solely create one occasion!");
}
occasion = this;
}
getInstance() {
return this;
}
getCount() {
return counter;
}
increment() {
return ++counter;
}
decrement() {
return --counter;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
// Error: You'll be able to solely create one occasion!
Excellent! Bây giờ tôi không thể tạo nhiều a number of cho occasion hơn nữa.
Hãy export Counter từ file counter.js. Nhưng trước khi làm điều đó, tôi nên đảm bảo rằng code không thể sửa đổi Singleton. Không thể thêm hoặc sửa các property của một đối tượng, điều này làm giảm rủi ro vô tình overwriting các worth trên Singleton.
let occasion;
let counter = 0;
class Counter {
constructor() {
if (occasion) {
throw new Error("You'll be able to solely create one occasion!");
}
occasion = this;
}
getInstance() {
return this;
}
getCount() {
return counter;
}
increment() {
return ++counter;
}
decrement() {
return --counter;
}
}
const singletonCounter = Object.freeze(new Counter());
export default singletonCounter;
—–DONE—–
Nhược điểm
Việc khởi tạo trong một occasion có thể tiết kiệm rất nhiều reminiscence. Thay vì phải tạo reminiscence cho từng occasion mỗi lần new
, tôi chỉ cần tạo 1 reminiscence cho 1 occasion đó, và reminiscence này được referenced cho toàn bộ app.
Tuy nhiên Singleton được coi là một anti-pattern, nên thường không được sử dụng trong Javascript.
Trong nhiều programming languages, như java, c++, c#, không thể trực tiếp tạo các object theo cách tôi có thể làm trong javascript. Trong OOP, chúng ta cần tạo một class, class này tạo ra object. Object được tạo đó có worth là occasion của class.
Tuy nhiên, việc implementation một class ở các ví dụ trên thật sự CHỈ ĐỂ HỌC CHO BIẾT THÔI CHỨ MÉO GIÚP ÍCH ĐƯỢC. Vì ngày nay ở một app ReactJS/NextJS, chúng ta thường sử dụng các international state thông qua các hệ sinh thái như Redux hoặc Context thay vì sử dụng Singletons. Mặc dù international state của chúng có vẻ tương tự như Singleton, nhưng chúng chỉ cho read-only state thay vì thay đổi trực tiếp state của Singleton. Khi sử dụng Redux/Context chỉ có operate reducers có thể replace các state, sau khi một part đã gửi một motion thông qua dispatcher.
Tóm cái quần lại, thay vì sử dụng Singleton để quản lý một app thì suy nghĩ nên dẹp đi, vì giờ đây đã có Redux/ Context.