Chào Mừng Đến Với Series Tìm Hiểu Design Pattern
Chào mừng anh em trở lại với series Design Pattern thực chiến trong lập trình hướng đối tượng. Hôm nay, chúng ta sẽ cùng nhau khám phá một trong những design pattern cơ bản và quan trọng – Prototype Pattern. Đây là một công cụ đắc lực giúp lập trình viên tối ưu hóa quy trình tạo ra các đối tượng mới mà không cần thiết lập lại mọi thứ từ đầu. Hãy cùng nhau tìm hiểu khái niệm, cơ chế hoạt động và cách implement Prototype Pattern trong Java, với các ví dụ cụ thể về Shallow Copy và Deep Copy nhé!
I. Khái Niệm Và Kiến Trúc
Theo cuốn Design Patterns: Elements of Reusable Object-Oriented Software, Prototype Pattern được định nghĩa như sau:
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
GoF
Mục tiêu chính của mẫu thiết kế này là tạo ra các đối tượng mới thông qua việc sao chép một prototype đã được xác định sẵn.
Cấu Trúc Tổng Quát
- Prototype: định nghĩa interface để phương thức clone.
- ConcretePrototype: triển khai phương thức
clone()
để clone chính nó. - Client: tạo instance mới bằng cách gọi phương thức
clone()
.
II. Shallow Copy Và Deep Copy
Shallow Copy và Deep Copy là hai phương pháp phổ biến để clone đối tượng trong Prototype pattern.
1. Shallow Copy
Khái Niệm
Shallow copy tạo ra một đối tượng mới mà không sao chép các đối tượng con, chỉ sao chép các tham chiếu tới chúng. Điều này có nghĩa là instance mới và instance gốc sẽ cùng trỏ tới các đối tượng con.
Cơ Chế
- Các thuộc tính kiểu nguyên thủy được sao chép giá trị.
- Các thuộc tính kiểu tham chiếu (array, list, object) chỉ sao chép tham chiếu, không sao chép dữ liệu thực sự của đối tượng con.
Hệ Quả
Bất kỳ thay đổi nào trong một đối tượng con sẽ được phản ánh ở cả clone instance và instance gốc. Điều này gây ra các side effects khó phát hiện, tạo ra sự ràng buộc giữa các instance.
2. Deep Copy
Khái Niệm
Deep copy tạo ra một instance mới và sao chép toàn bộ cấu trúc dữ liệu của instance gốc, bao gồm việc sao chép độc lập tất cả các đối tượng con.
Cơ Chế
Các thuộc tính có kiểu nguyên thủy được sao chép giá trị, còn thuộc tính kiểu tham chiếu được khởi tạo một bản sao hoàn toàn mới.
Hệ Quả
Deep copy giúp tách biệt clone instance và instance gốc, tránh phát sinh side effect. Tuy nhiên, nó tiêu tốn nhiều tài nguyên hơn so với shallow copy.
3. So Sánh
III. Thực Hành Implement Trong Java
1. Shallow Copy
Shape | Prototype
java
public abstract class Shape {
int x;
int y;
public Shape() {
}
public Shape(Shape target) {
if (Objects.nonNull(target)) {
this.x = target.x;
this.y = target.y;
}
}
public abstract Shape clone();
}
Circle | Concrete Prototype
java
public class Circle extends Shape {
private int radius;
private int[] color;
public Circle() {
}
public Circle(Circle target) {
super(target);
if (Objects.nonNull(target)) {
this.radius = target.radius;
System.out.println("Shallow copy");
this.color = target.color;
}
}
@Override
public Shape clone() {
return new Circle(this);
}
}
App | Client
java
public class App {
public static void main(String[] args) {
Circle circle = createCircle();
Circle cloneCircle = (Circle) circle.clone();
System.out.println(circle.equals(cloneCircle) ? "They are EQUAL" : "They are not EQUAL");
int[] color = cloneCircle.getColor();
color[0] = 200;
System.out.printf("Original color = %s%n", Arrays.toString(circle.getColor()));
System.out.printf("Clone color = %s%n", Arrays.toString(cloneCircle.getColor()));
}
}
Output
Shallow copy
They are EQUAL
Original color = [200, 255, 255]
Clone color = [200, 255, 255]
They are EQUAL
2. Deep Copy
Chỉ cần thay đổi nhỏ trong phương thức clone()
của Circle
sử dụng clone()
của mảng để thực hiện deep copy:
java
public Circle(Circle target) {
super(target);
if (Objects.nonNull(target)) {
this.radius = target.radius;
System.out.println("Deep copy");
this.color = target.color.clone();
}
}
Output
Deep copy
They are EQUAL
Original color = [255, 255, 255]
Clone color = [200, 255, 255]
They are not EQUAL
IV. Kết Luận
Chúng ta đã tìm hiểu về Prototype Pattern – một giải pháp hiệu quả trong việc tạo ra các đối tượng mới từ một prototype có sẵn. Qua phân tích Shallow Copy và Deep Copy, hy vọng anh em đã hiểu rõ hơn về cách hoạt động và các điểm cần lưu ý khi triển khai pattern này trong thực tế. Việc lựa chọn phương pháp copy phụ thuộc vào ngữ cảnh và yêu cầu của dự án cụ thể. Hãy áp dụng những gì học được một cách khôn ngoan để đảm bảo sản phẩm của bạn không chỉ hoạt động hiệu quả mà còn không gặp phải các vấn đề không lường trước.
Cảm ơn anh em đã theo dõi bài viết. Hẹn gặp lại trong các bài viết tiếp theo!
Tài Liệu Tham Khảo
- Refactoring.guru
- Head First Design Patterns - O'Reilly
- Design Patterns: Elements of Reusable Object-Oriented Software - GoF
Nếu bài viết hữu ích, đừng ngần ngại click upvote hoặc để lại ý kiến và thảo luận với tôi nhé! Bạn có thể theo dõi thêm các bài viết khác của tôi tại Blog cá nhân hoặc kết nối trên Linkedin.
source: viblo