Học Design Pattern: Prototype Pattern
Đặt vấn đề
Trong nhiều tình huống, chúng ta cần tạo ra các đối tượng mới mà có nhiều điểm tương đồng với các đối tượng đã tồn tại. Việc tạo ra các đối tượng này từ đầu có thể tốn kém về thời gian và tài nguyên, đồng thời dễ gây ra sai sót nếu tạo chúng một cách thủ công.
Hãy tưởng tượng rằng bạn đang xây dựng một ứng dụng chỉnh sửa đồ họa. Ứng dụng này cho phép người dùng tạo ra các hình dạng khác nhau, chẳng hạn như hình chữ nhật, hình tròn và hình tam giác. Người dùng thường xuyên tạo ra các hình dạng mới có cùng thuộc tính (ví dụ: màu sắc, độ dày đường viền) với các hình dạng đã tạo trước đó.
Thách thức ở đây là làm sao để tạo ra các hình dạng mới một cách hiệu quả, tránh việc phải thiết lập lại các thuộc tính giống nhau mỗi lần tạo.
Code Không Dùng Prototype Pattern
class Shape(
var color: String,
var borderWidth: Int,
val shapeType: String
)
class ShapeFactory {
fun createShape(type: String, color: String, borderWidth: Int): Shape {
return Shape(color, borderWidth, type)
}
}
fun main() {
val factory = ShapeFactory()
val redRectangle = factory.createShape("Rectangle", "red", 2)
val anotherRedRectangle = factory.createShape("Rectangle", "red", 2) // Tạo hình chữ nhật đỏ tương tự
val blueCircle = factory.createShape("Circle", "blue", 1)
println(redRectangle)
println(anotherRedRectangle)
println(blueCircle)
}
Ở đây, chúng ta phải truyền các thuộc tính (màu sắc, độ dày đường viền) vào hàm createShape
mỗi khi tạo hình, ngay cả khi chúng giống nhau.
Code Dùng Prototype Pattern
interface Shape {
fun draw()
}
data class Rectangle(
var color: String,
var borderWidth: Int
) : Shape {
override fun draw() {
println("Drawing a $color rectangle with border width $borderWidth")
}
}
data class Circle(
var color: String,
var borderWidth: Int
) : Shape {
override fun draw() {
println("Drawing a $color circle with border width $borderWidth")
}
}
fun main() {
val prototypeRectangle = Rectangle("red", 2) // Prototype
val redRectangle1 = prototypeRectangle.copy() as Rectangle
redRectangle1.color = "red"
redRectangle1.borderWidth = 2
redRectangle1.draw()
val redRectangle2 = prototypeRectangle.copy() as Rectangle
redRectangle2.color = "red"
redRectangle2.borderWidth = 2
redRectangle2.draw()
val blueCircle = Circle("blue", 1)
blueCircle.draw()
}
Ở đây, chúng ta tạo một đối tượng “prototype” (prototypeRectangle
) và sử dụng hàm copy()
để tạo ra các bản sao của nó. Sau đó, chúng ta có thể tùy chỉnh các thuộc tính của các bản sao này.
Bài Học Từ Prototype Pattern
Prototype Pattern giúp chúng ta:
- Tạo ra các đối tượng mới dựa trên các đối tượng hiện có.
- Tránh việc tạo lại các đối tượng từ đầu, tiết kiệm thời gian và tài nguyên.
- Tăng tính linh hoạt trong việc tạo ra các biến thể của đối tượng.
Khi thiết kế hệ thống, hãy cân nhắc sử dụng Prototype Pattern khi bạn cần tạo ra nhiều đối tượng tương tự nhau và muốn tối ưu hóa quá trình tạo.