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.
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.
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.