# Hướng dẫn Prototype Pattern trong Java

### 1\. Giới thiệu Prototype Pattern

**Prototype Pattern** là một mẫu thiết kế thuộc nhóm Creational Patterns, được sử dụng để tạo các đối tượng mới bằng cách sao chép một đối tượng hiện có, thay vì khởi tạo từ đầu. Điều này rất hữu ích khi việc khởi tạo một đối tượng tốn kém tài nguyên và thời gian.

### 2\. Các trường hợp ứng dụng Prototype Pattern

* **Khởi tạo đối tượng tốn kém**: Khi quá trình khởi tạo một đối tượng phức tạp và tốn kém tài nguyên.
    
* **Đảm bảo tính nhất quán**: Khi cần nhiều đối tượng có cấu hình giống nhau hoặc chỉ thay đổi chút ít.
    
* **Tăng hiệu suất**: Khi cần tạo nhiều đối tượng nhanh chóng bằng cách sao chép thay vì khởi tạo từ đầu.
    

### 3\. Triển khai Prototype Pattern

#### 3.1. Ví dụ triển khai đơn giản

Trong ví dụ này, chúng ta sẽ tạo một lớp `Shape` với các lớp con `Circle` và `Rectangle`, và sử dụng Prototype Pattern để sao chép các đối tượng.

```java
import java.util.HashMap;
import java.util.Map;

// Bước 1: Tạo interface Cloneable
public abstract class Shape implements Cloneable {
    private String id;
    protected String type;
    
    abstract void draw();
    
    public String getType() {
        return type;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

// Bước 2: Tạo các lớp con
public class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}

public class Rectangle extends Shape {
    public Rectangle() {
        type = "Rectangle";
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a Rectangle");
    }
}

// Bước 3: Tạo lớp quản lý Prototype
public class ShapeCache {
    private static Map<String, Shape> shapeMap = new HashMap<>();
    
    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }
    
    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);
        
        Rectangle rectangle = new Rectangle();
        rectangle.setId("2");
        shapeMap.put(rectangle.getId(), rectangle);
    }
}

// Bước 4: Sử dụng Prototype Pattern
public class PrototypePatternDemo {
    public static void main(String[] args) {
        ShapeCache.loadCache();
        
        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape : " + clonedShape1.getType());
        clonedShape1.draw();
        
        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape : " + clonedShape2.getType());
        clonedShape2.draw();
    }
}
```

#### 3.2. Ví dụ triển khai phức tạp

Giả sử chúng ta có một lớp `Employee` với nhiều thuộc tính và quá trình khởi tạo tốn kém.

```java
import java.util.ArrayList;
import java.util.List;

// Bước 1: Tạo lớp Employee
public class Employee implements Cloneable {
    private List<String> employeeList;
    
    public Employee() {
        employeeList = new ArrayList<>();
    }
    
    public Employee(List<String> list) {
        this.employeeList = list;
    }
    
    public void loadData() {
        // Giả sử đây là quá trình khởi tạo tốn kém tài nguyên
        employeeList.add("John");
        employeeList.add("Jane");
        employeeList.add("Jack");
        employeeList.add("Julie");
    }
    
    public List<String> getEmployeeList() {
        return employeeList;
    }
    
    @Override
    public Object clone() {
        List<String> temp = new ArrayList<>(this.employeeList);
        return new Employee(temp);
    }
}

// Bước 2: Sử dụng Prototype Pattern
public class PrototypePatternDemo {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        emp1.loadData();
        
        Employee emp2 = (Employee) emp1.clone();
        Employee emp3 = (Employee) emp1.clone();
        
        List<String> list1 = emp2.getEmployeeList();
        list1.add("Emma");
        
        List<String> list2 = emp3.getEmployeeList();
        list2.remove("John");
        
        System.out.println("Employee List 1: " + emp1.getEmployeeList());
        System.out.println("Employee List 2: " + list1);
        System.out.println("Employee List 3: " + list2);
    }
}
```

### 4\. Phân tích các trường hợp ứng dụng Prototype Pattern

#### 4.1. Khởi tạo đối tượng tốn kém

* **Ưu điểm**: Giảm thiểu tài nguyên và thời gian khởi tạo bằng cách sao chép đối tượng thay vì khởi tạo lại từ đầu.
    
* **Nhược điểm**: Cần quản lý quá trình sao chép một cách cẩn thận để tránh các vấn đề liên quan đến bản sao và bản gốc.
    

#### 4.2. Đảm bảo tính nhất quán

* **Ưu điểm**: Dễ dàng tạo ra các đối tượng có cấu hình giống nhau hoặc chỉ thay đổi chút ít, đảm bảo tính nhất quán trong ứng dụng.
    
* **Nhược điểm**: Cần đảm bảo rằng các thuộc tính được sao chép chính xác và không bị thay đổi ngoài ý muốn.
    

#### 4.3. Tăng hiệu suất

* **Ưu điểm**: Tạo nhiều đối tượng nhanh chóng bằng cách sao chép thay vì khởi tạo từ đầu, giúp tăng hiệu suất của ứng dụng.
    
* **Nhược điểm**: Cần quản lý bộ nhớ một cách hiệu quả để tránh lãng phí tài nguyên.
    

### 5\. Kết luận

Prototype Pattern là một mẫu thiết kế mạnh mẽ và hữu ích, đặc biệt khi cần tạo các đối tượng phức tạp hoặc khởi tạo tốn kém trong Java. Việc hiểu và áp dụng đúng Prototype Pattern sẽ giúp lập trình viên xây dựng các hệ thống dễ bảo trì, dễ mở rộng và hiệu quả hơn.
