Chúng ta sẽ đi vào phân tích chức năng và cách sử dụng của 2 pattern đầu tiên trong nhóm Creational là Singleton và Prototype

1. Singleton

Phương châm của Singleton là hãy define một instance duy nhất cho một class và làm cho nó phục vụ toàn hệ thống. Nói cách khác chúng ta phải đảm bảo rằng với một class nào đó chỉ có duy nhất 1 instance được tạo ra và những class khác đều có thể sử dụng được nó.:

Lợi ích

Hiển nhiên là tiết kiệm được bộ nhớ sử dụng do đối tượng được tạo ra 1 và chỉ, sau đó sẽ được toàn bộ sử dụng.

Khi nào nên sử dụng:

Singleton được ứng dụng khá nhiều nhất là trong các ứng dụng multi-threaded, ứng dụng web cũng là một trong những ứng dụng multi-thread. Khi xử lý nhiều thread khác nhau với những luồng xử lý khác nhau, có những thành phần chúng ta chỉ cần khởi tạo 1 lần duy nhất và tái sử dụng chúng qua lại giữa các thread: 

  • Các class chuyên xử lý hàm static 
  • Database connection
  • Ghi log của Hệ thống và Người dùng.
  • Quản lý Pool resource.

Để có thể tạo được những class tuân theo chuẩn Singleton chúng ta cần đảm bảo các yếu tố sau cho chúng:

  1. static method hoặc static field: Do chỉ có 1 instance duy nhất nên việc lấy data từ bên trong class chỉ có thể thông qua các hàm static mà không phải là getter hoặc setter bình thường.
  2. private constructor: Điểu này sẽ gíup chúng ta đảm bảo rằng sẽ không thể khởi tạo được instance của class này bằng toán tử new.

Sơ đồ UML:

Code sample:

public class SingleTonClass {
    private static SingleTonClass obj = new SingleTonClass();//Early, instance will be created at load time

    private SingleTonClass(){} //prevent to be created by new

    public static SingleTonClass getInstance(){
        return obj;
    }

    public void doSomething(){
        //write your code
    }
}

public class OutSideClass{
    
    public void doSomethingWithSingleTon(){
        SingleTonClass onlyInstance = SingleTonClass.getInstance();
        onlyInstance.doSomething();
    }
}

Như ví dụ trên chúng ta có thể thấy rằng class SingleTonClass chỉ có thể có duy nhất 1 instance được khởi tạo ngay bên trong nội bộ class của nó và được get ra bằng hàm static. Các class khác sẽ sử dụng class  SingleTonClass bằng cách gọi hàm getInstance và thực hiện method.

 

2. Prototype:

Phương châm của Prototype: thay vì tạo mới 1 instance (bằng new) thì hãy clone ra từ một đối tượng đã có sẵn để có thể giảm resource dành cho việc tạo mới, sau đó chỉ việc thay đổi lại giá trị mong muốn.

Lợi ích

Lợi ích như phương châm đã trình bày là giảm được resource (RAM, CPU) và thời gian xử lý cho việc tạo mới. Với những bạn chưa có kinh nghiệm tiếp xúc với các dự án lớn, với những class có hàng chục field thậm chí cả trăm field thì việc tạo mới cũng ít nhiều ảnh hưởng đến tài nguyên hệ thống. Các bạn có thể lập luận rằng nếu chúng ta đang vận hành một Hệ thống lớn thì hiển nhiên chúng ta đang có Server với nhiều tài nguyên thì chắc không cần lo đến việc cỏn con. Tuy nói là vậy, nhưng trong thực tế việc tiết kiệm được phần nào sẽ làm giảm đi chi phí phần đó, mang lại nhiều lợi nhuận hơn cho dự án và thành viên của dự án. 

Tất nhiên ở đây chúng ta chỉ đang bàn đến việc sử dụng Design Pattern thôi nhé, những vấn đề to hơn có dịp thì chúng ta sẽ cùng nhau bàn luận :)

Ví dụ chúng ta có 1 class với 1 trăm field, các bạn hãy tưởng tượng khi tạo mới một đối tượng thì bằng toán tử new thì việc đầu tiên là JVM phải cấp phát bộ nhớ cho đối tượng với các trường chưa có dữ liệu (hoặc dữ liệu mặc định) , tiếp theo tất nhiên chúng ta sẽ set dữ liệu vào, các vùng nhớ của các field sẽ lần lượt được cấp phát mở rộng và tốn thêm thời gian để ghi dữ liệu vào. Thay vào đó, nếu chúng ta đã có sẵn 1 đối tượng đươcj khởi tạo thì việc clone (nhân bản) nó ra đối tượng sẽ nhanh hơn nhiều vì việc đọc và copy các mã nhị phân thì tầng JVM làm trực tiếp sẽ nhanh hơn thông qua các câu lệnh nhiều. Sau đó chúng ta chỉ cần việc set lại các giá trị mà chúng ta cần.

Khi nào nên sử dụng:

  • Khi việc tạo ra đối tượng tốn nhiều resource và có logic phức tạp.
  • Khi Hệ thống cần giữ số lượng instance được tạo ra ở mức thấp nhất có thể. Ví dụ cho bài toán tạo Server cho các Hệ thống Quản lý tính toán:  Khi cần huy động sức mạnh tính toán, chương trình sẽ clone các Server  (application) ra tăng sức xử lý cho Hệ thống. Sau khi xong việc tất nhiên chúng phải bị thu hồi và sử dụng cho mục đích khác. Thường thấy trong các Hệ thống share host hoặc Cloud host.
  • Khi Client cần quản lý số lượng instance được tạo ra. Cũng với bài toán Server ví dụ nhu trên.

Sơ đồ UML:

Hướng dẫn code:

Đầu tiên chúng ta phải có 1 interface Prototype trước

public interface Prototype {  
     public Prototype getClone();  
}

Interface này chí có 1 hàm duy nhất là getClone, kiểu dữ liệu trả về là Prototype hay nói cách khác là chính bản thân nó.

Tiếp theo là nhân vật chính (class được clone), ví dụ sau chỉ đơn giản với class chỉ có 4 field:

public class Employee implements Prototype{

    private int id;
    private String name, designation;
    private double salary;
    private String address;

    public Employee(){
        System.out.println("   Employee Records of Oracle Corporation ");
        System.out.println("---------------------------------------------");
        System.out.println("Eid"+"\t"+"Ename"+"\t"+"Edesignation"+"\t"+"Esalary"+"\t\t"+"Eaddress");

    }

    public Employee(int id, String name, String designation, double salary, String address) {

        this();
        this.id = id;
        this.name = name;
        this.designation = designation;
        this.salary = salary;
        this.address = address;
    }

    public void showRecord(){

        System.out.println(id+"\t"+name+"\t"+designation+"\t"+salary+"\t"+address);
    }

    @Override
    public Prototype getClone() {
        return new Employee(id,name,designation,salary,address);
    }
}

Class Employee sẽ implement hàm getClone bằng cách gọi lại Constructor của nó.

Chúc các bạn thành công.

AutoCode.VN

minhnhatict@gmail.com Creational Pattern