+116

Học Singleton Pattern trong 5 phút.

Đặt vấn đề

Trong bài viết này mình sẽ giúp các bạn trả lời 4 câu hỏi về Single pattern trong vòng 5 phút.

  1. Singleton Pattern là gì?
  2. Tại sao cần dùng Singleton Pattern
  3. Làm thế nào để implement Singleton Pattern
  4. Có những cách nào để implement Singleton Pattern Liệu có đủ không nhỉ các bạn cùng theo dõi nhé

1. Single Pattern là gì?

Theo Gang of Four patterns một cuốn sách rất nổi tiếng về design pattern thì Single Pattern là một design pattern trong số 5 design pattern thuộc nhóm Creational Design Pattern

Creational Structure Behavioral
Abstract factory Adapter Chain of responsibility
Builder Bridge Command
Factory Composite Interpreter
Prototype Decorator Iterator
#Singleton Facade Mediator
Flyweight Memento Memento
Proxy Observer
Strategy
Template Method
Visitor

Single Pattern là một design pattern mà

  1. Đảm bảo rằng một class chỉ có duy nhất một instance (khởi tạo - mình xin phép để nguyên không dịch từ này)
  2. Và cung cấp một cáchs toàn cầu để truy cấp tới instance đó.

Vậy tại sao cần phải sử dụng Single Pattern

2. Tại sao cần dùng Singleton Pattern?

Hầu hết các đối tượng trong một ứng dụng đều chịu trách nhiệm cho công việc của chúng và truy xuất dữ liệu tự lưu trữ (self-contained data) và các tham chiếu trong phạm vi được đưa ra của chúng. Tuy nhiên, có nhiều đối tượng có thêm những nhiệm vụ và có ảnh hưởng rộng hơn, chẳng hạn như quản lý các nguồn tài nguyên bị giới hạn hoặc theo dõi toàn bộ trạng thái của hệ thống. Ví dụ có thể có rất nhiều máy in trong hệ thống nhưng chỉ có thể tồn tại duy nhất một Sprinter Spooler (Phần quản lý máy in)

Hay

giả sử trong ứng dụng có chức năng bật tắt nhạc nền chẳng hạn, khi người dùng mở app thì ứng dụng sẽ tự động mở nhạc nền và nếu người dùng muốn tắt thì phải vào setting trong app để tắt nó, trong setting của app cho phép người dùng quản lí việc mở hay tắt nhạc, và trong trường hợp này bạn sẽ cần sử dụng singleton để quản lí việc này. Chắc chắn bạn phải cần duy nhất 1 instance để có thể ra lệnh bật hay tắt, tại sao ? vì đơn giản bạn không thể tạo 1 instance để mở nhạc rồi sau đó lại tạo 1 instance khác để tắt nhạc, lúc này sẽ có 2 instance được tạo ra, 2 instance này không liên quan đến nhau nên không thể thực hiện thực hiện việc cho nhau được, bạn phải hiểu rằng instance nào bật thì chỉ có instance đó mới được phép tắt nên dẫn đến phải cần 1 instance.

3.Làm thế nào để implement Singleton Pattern

Vậy là thế nào để có thể implement Singleton Pattern chúng ta cần trả lời 2 câu hỏi.

  1. Làm sao để 1 class chỉ có thể có duy nhất 1instance? Trả lời
  • Private constructor của class đó để đảm bảo rằng class lớp khác không thể truy cập vào constructor và tạo ra instance mới
  • Tạo một biến private static là thể hiện của class đó để đảm bảo rằng nó là duy nhất và chỉ được tạo ra trong class đó thôi.
  1. Làm sao để có thể ccung cấp một cáchs toàn cầu để truy cấp tới instance đó. Trả lời
  • Tạo một public static menthod trả về instance vừa khởi tạo bên trên, đây là cách duy nhất để các class khác có thể truy cập vào instance của class này

Vậy cụ thể có những cách nào để implement Singleton Pattern

4. Có những cách nào để implement Singleton Pattern

4.1 Eager initialization

public class EagerInitializedSingleton {

   private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();

   //private constructor to avoid client applications to use constructor
   private EagerInitializedSingleton(){}

   public static EagerInitializedSingleton getInstance(){
       return instance;
   }
}

Đây là cách dễ nhất nhưng nó có một nhược điểm là mặc dù instance đã được khởi tạo nhưng có thể sẽ không dùng tới. vì vậy chúng ta có cách thứ 2.

4.2 Lazy initialization

public class LazyInitializedSingleton {

    private static LazyInitializedSingleton instance;

    private LazyInitializedSingleton(){}

    public static LazyInitializedSingleton getInstance(){
        if(instance == null){
            instance = new LazyInitializedSingleton();
        }
        return instance;
        }
}

Cách này đã khắc phục được nhược điểm của cách 1 Eager initialization, chỉ khi nào geInstance được gọi thì instance mới được khởi tạo. Tuy nhiên cách này chỉ sử dụng tốt trong trường hợp đơn luồng, trường hợp nếu có 2 luồng cùng chạy và cùng gọi hàm getInstance tại cùng một thời điểm thì đương nhiên chúng ta có ít nhất 2 thể hiện của instance. Vậy ta phải làm sao với trường hợp đa luồng. chúng ta đi tới cách tiếp theo

4.3 Thread Safe initialization

public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton(){}

    public static synchronized ThreadSafeSingleton getInstance(){
        if(instance == null){
            instance = new ThreadSafeSingleton();
        }
        return instance;
     }

Cách đơn gảin nhất là chúng ta gọi phương thức synchronized của hàm getInstance() và như vậy hệ thống đảm bảo rằng tại cùng một thời điểm chỉ có thể có 1 luồng có thể truy cập vào hàm getInstance(), và đảm bảo rằng chỉ có duy nhất 1 thể hiện của class Tuy nhiên một menthod synchronized sẽ chạy rất chậm và tốn hiệu năng vì vậy chúng ta cần cải tiến nó đi 1 chút.

4.4 Thread Safe Upgrade initialization

Mình tạm gọi nó là Thread Safe Upgrade initialization, thay vì chúng ta Thread Safe cả menthod getInstance() chúng ta chỉ Thread Safe một đoạn mã quan trong

ublic class ThreadSafeSingleton {
    private static ThreadSafeSingleton instance;
    private ThreadSafeSingleton(){}

    public static ThreadSafeSingleton getInstance(){
        if(instance == null){
            synchronized(ThreadSafeSingleton.class){
                if(instance == null){
                   instance = new ThreadSafeSingleton();
                }
            }
        }
        return instance;
     }
}

Có rất nhiều cách implement cho Singleton, mình thì hay sử dụng cách 2 cho những ứng dụng chỉ làm việc với 1 thread và cách thứ 4 cho trường hợp đa luồng. Các bạn hãy chọn cho mình cách implement phù hợp cho từng trường hợp nhé.👍 Trên đây là phần giới thiệu của mình về Singleton, các bạn có thể tham khảo slide của mình tại link sau https://goo.gl/KUtZsW. Chúc các bạn học tốt!


All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@hieutrung
thg 5 4, 2018 2:30 CH

cảm ơn bạn. Bài viết khá đầy đủ

Avatar
@doan.van.toan
thg 6 27, 2018 3:36 SA

you're welcome. 😄

Avatar
@chiro
thg 1 28, 2019 2:26 SA
Avatar
@doan.van.toan
thg 1 30, 2019 1:28 SA

Dear @chiro, Cám ơn bạn đã đón đoc bài viết của mình, Mcục đích của việc tạo biến private là để đảo bảo tính đóng gói trong lập trình hướng đối tượng, khiến cho các class khác không thể truy cập hay thay đổi giá trị của thể hiện đó.

Avatar
@Kaiser
thg 6 28, 2019 1:47 CH

em có một class có biến private, để một class khác có thể lấy biến đó để xử lý thì trong class trước đó em khai báo thêm một biến publicstatic cùng kiểu, rồi gán giá trị biến private cho nó. Mọi thứ hoạt động khá tốt. Thế cho em hỏi đó có phải là singleton không ạ, hay em làm sai ạ?

Avatar
@doan.van.toan
thg 7 5, 2019 3:17 SA

@Kaiser theo anh thi èm xử lý như vậy có thể giải quyết được bài toán, nhưng về mặt singleton thì không phải em ạ Singleton là các đảm bảo 1 class chỉ có duy nhất 1 khởi tạo (instance) Ở đây e chỉ đảm bảo rằng có 1 cách truy xuất tới biến private của class em tạo ra thôi, chứ k đảm bảo class đó chỉ có duy nhất 1 khởi tạo.

Avatar
@tienvm
thg 5 7, 2021 8:14 SA
  1. Cảm ơn bài viết của bạn
  2. "Làm sao để có thể ccung cấp một cáchs toàn cầu để truy cấp tới instance đó". Từ toàn cầu trong câu này của bạn có phải là global? Nếu là global thì mình nghĩ để global sẽ dễ hiểu với dev mình hơn mà nghe nó cũng đỡ cấn cấn :v Ý kiến cá nhân của mình
  3. Ngoài ra bài này chính tả nhiều chỗ thừa chữ :v
Avatar
@thong20
thg 10 28, 2021 1:59 CH

Em chưa hiểu ý đồ 2 lần kiểm tra instance == null của tác giả ạ?

Avatar
@ducanhcules
thg 4 25, 2022 4:19 SA
Avatar
@thanhlongst2013
thg 1 19, 2023 2:05 SA

Bài viết hay. Cảm ơn anh !

Avatar

Một bài viết rất đầy đủ những gì em cần biết khi mới học tuyệt vời. Cảm ơn anh!

Avatar

Cam on anh nhe. Bai viet rat day du va de hieu. Ben em lam automation test voi Java, khi muon thuc thi da luong (parallel testing) cung can set-up de toi uu nhieu phan nhu the nay. Singleton pattern + ThreadLocal la du.

Avatar
+116
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí