Trong Java, khi tạo một đối tượng mới thì các thuộc tính của đối tượng chưa được khởi tạo ngoại trừ các giá trị mặc định được khởi tạo trong constructor. Tuy nhiên, thay vì tạo mới một đối tượng thì ta lại muốn sao chép một đối tượng khác đã tồn tại. Việc này là hoàn toàn có thể đạt được nếu các đối tượng được cài đặt theo Prototype Pattern, một đối tượng được khởi tạo với đủ các thuộc tính sẽ là khuôn mẫu để các đối tượng khác có thể sao chép. Chi tiết về Prototype Pattern sẽ được Stringee giới thiệu tới các bạn trong bài viết này.

1. Prototype Pattern trong Java là gì?

Prototype Pattern là một trong những Creational Pattern. Nó có nhiệm vụ khởi tạo một đối tượng bằng cách clone một đối tượng đã tồn tại thay vì khởi tạo với từ khóa new. Đối tượng mới là một bản sao có thể giống 100% với đối tượng gốc, chúng ta có thể thay đổi dữ liệu của nó mà không ảnh hưởng đến đối tượng gốc.

Prototype Pattern được dùng khi việc tạo một đối tượng quá tốn kém chi phí và thời gian trong khi đó đã tồn tại một đối tượng tương tự.

Trong Java cung cấp mẫu Prototype Pattern này bằng việc implement interface Cloneable và sử dụng method clone() để tạo object có đầy đủ thuộc tính của đối tượng ban đầu.

>>> Xem thêm bài viết:

- Khai báo và sử dụng mảng các đối tượng trong Java

- Phân biệt ArrayList, Set và Vector trong Java

- Lập trình đa luồng là gì? Hướng dẫn lập trình đa luồng bằng ngôn ngữ Java

2. Cài đặt Prototype trong Java như thế nào?

2.1. Các thành phần cơ bản của Prototype trong Java

Một Prototype Pattern gồm các thành phần cơ bản sau:

Prototype : khai báo một class, interface hoặc abstract class cho việc clone chính nó.

Concrete Prototype class : các lớp này thực thi interface (hoặc kế thừa từ lớp abstract) được cung cấp bởi Prototype để copy (nhân bản) chính bản thân nó. Các lớp này chính là thể hiện cụ thể phương thức clone(). Lớp này có thể không cần thiết nếu: Prototype là một class và nó đã implement việc clone chính nó.

Client class : tạo mới object bằng cách gọi Prototype thực hiện clone chính nó.

2.2. Ví dụ

Chúng ta đang cần một danh sách để quản lý các máy tính trong một văn phòng, các máy tính thì đều có thông số, tên, thời lượng sử dụng là như nhau. Ở đây, chúng ta có thể tạo ra một đối tượng máy tính từ lớp sau:

public class Computer implements Cloneable{

    private int id;
    private String name;
    private int age;
    private String os;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    @Override
    protected Computer clone() throws CloneNotSupportedException {
        return (Computer) super.clone();
    }

    @Override
    public String toString() {
        return "Computer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", os='" + os + '\'' +
                '}';
    }

}

Các máy tính chỉ khác nhau giá trị id: là mã định danh ta sẽ điền để thực hiện giám sát. Sau đây là chương trình để tạo ra 10 máy tính với một vòng lặp:

public class CheckListComputerMain {

    public static void main(String[] args) {

        long startTime = System.currentTimeMillis();

        for (int index = -1; ++index < 10; ) {

            Computer computer = new Computer();
            computer.setName("Computer level promax");
            computer.setAge(2);
            computer.setOs("Windows");

            computer.setId(index);
            System.out.println(computer);

        }

        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Time process is: " + duration);
    }

}

Ta có thể thấy việc khởi tạo các đối tượng qua các vòng lặp sử dụng các thông số gần như là không đổi, từ đó ta có thể viết lại phương thức main sử dụng Prototype như sau:

public class CheckListComputerMainPrototype {

    public static void main(String[] args) throws CloneNotSupportedException {

        Computer computer = new Computer();
        computer.setName("Computer level promax");
        computer.setAge(2);
        computer.setOs("Windows");

        long startTime = System.currentTimeMillis();

        for (int index = -1; ++index < 10; ) {
            Computer computer1 = computer.clone();
            computer1.setId(index);
            System.out.println(computer1);
        }

        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Time process is: " + duration);
    }

}

Xem thêm bài viết về chủ đề ngôn ngữ lập trình Java:

- Tìm hiểu về Singleton pattern trong Java

- Tìm hiểu về design pattern factory trong java

- Xử lý timezone trong Java

3. Lợi ích của Prototype Pattern là gì?

Cải thiện performance: giảm chi phí tạo một đối tượng mới theo chuẩn giúp tăng hiệu suất phần mềm so với việc dùng từ khóa new để tạo đối tượng mới

Giảm độ phức tạp cho việc khởi tạo đối tượng: do mỗi lớp chỉ implement cách clone của chính nó.

Giảm việc phân lớp, tránh việc tạo nhiều lớp con cho việc khởi tạo đối tượng như của Abstract Factory Pattern.

Khởi tạo đối tượng mới bằng cách thay đổi một vài thuộc tính của object : Một hệ thống linh động sẽ để cho chúng ta tự định nghĩa một hành động nào đó thông qua sự kết hợp với một đối tượng hơn là định nghĩa một class mới.

Khởi tạo đối tượng mới bằng cách thay đổi cấu trúc: Rất nhiều ứng dụng xây dựng hệ thống từ nhiều phần và các phần con. Các phần con lại khởi tạo từ nhiều phần con khác (chia nhỏ bài toán). Prototype Pattern cũng hỗ trợ điều này. Nghĩa là các phần đó có thể được khởi tạo từ việc copy một nguyên mẫu từ một “cấu trúc” khác. Miễn là các phần kết hợp đều thể hiện clone() và được sử dụng với cấu trúc khác nhau làm nguyên mẫu. Xem thêm về Object cloning trong java bạn sẽ thấy rõ điều này.

4. Sử dụng Prototype Pattern trong Java khi nào?

Chúng ta có một object và cần phải tạo 1 object mới khác dựa trên object bạn đầu mà không thể sử dụng toán tử new hay các hàm constructor để khởi tạo. Vì sao vậy? Lý do đơn giản là ở đây chúng ta ko hề được biết thông tin nội tại của object đó hoặc object đó đã có thể bị che dấu đi nhiều thông tin khác mà chỉ cho ta một thông tin rất giới hạn không đủ để hiểu được. Do vậy ta không thể dùng toán tử new để khởi tạo nó được. Giải pháp là để cho chính object mẫu tự xác định thông tin và dữ liệu sao chép.

Khởi tạo đối tượng lúc run-time: chúng ta có thể xác định đối tượng cụ thể sẽ được khởi tạo lúc runtime nếu class được implement / extend từ một Prototype.

Cấu hình một ứng dụng với dynamic class.

Muốn truyền đối tượng vào một hàm nào đó để xử lý, thay vì truyền đối tượng gốc có thể ảnh hưởng dữ liệu thì ta có thể truyền đối tượng sao chép.

Chi phí của việc tạo mới đối tượng (bằng cách sử dụng toán tử new) là lớn.

Ẩn độ phức tạp của việc khởi tạo đối tượng từ phía Client.

Kết

Prototype Pattern là một khuôn mẫu phù hợp cho việc khởi tạo các đối tượng tốn nhiều tài nguyên do nó cho phép sao chép các thuộc tính từ một đối tượng khác. Việc sử dụng hiệu quả phương thức này mang lại nhiều lợi ích trong quá trình phát triển phần mềm với Java. Trong các bài viết tiếp theo, Stringee sẽ mang lại cho các bạn nhiều hơn các kiến thức liên quan đến lập trình, hãy cùng theo dõi nhé.


Stringee Communication APIs là giải pháp cung cấp các tính năng giao tiếp như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài CSKH cho phép tích hợp trực tiếp vào ứng dụng/website của doanh nghiệp nhanh chóng. Nhờ đó giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp bởi thông thường nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.

Bộ API giao tiếp của Stringee hiện đang được tin dùng bởi các doanh nghiệp ở mọi quy mô, lĩnh vực ngành nghề như TPBank, VOVBacsi24, VNDirect, Shinhan Finance, Ahamove, Logivan, Homedy,  Adavigo, bTaskee…

Quý bạn đọc quan tâm xin mời đăng ký NHẬN TƯ VẤN TẠI ĐÂY: