1. Mô hình Decorator là gì

Mô hình decorator là một mô hình thiết kế cấu trúc cho phép thêm các tính năng bổ sung vào một đối tượng một cách linh động mà không cần sửa đổi mã nguồn của đối tượng. Điều này được thực hiện bằng cách bọc đối tượng trong một lớp Decorator, cung cấp khả năng thêm, sửa đổi hoặc cải thiện hành vi của đối tượng tại thời điểm chạy.

2. Đặc điểm và Ưu điểm của Mô hình Decorator

Các đặc điểm và ưu điểm của mô hình decorator bao gồm:

  • Mở rộng tính năng của một đối tượng một cách linh hoạt mà không cần sửa đổi mã nguồn ban đầu.
  • Tuân theo Nguyên lý Mở-Đóng, cho phép thêm và loại bỏ các decorator một cách linh động.
  • Có khả năng kết hợp nhiều decorator để mở rộng tính năng theo cấp độ lồng nhau.
  • Độc lập giữa các decorator và cách đối tượng được trang trí, cho phép sự thay đổi được thực hiện một cách độc lập.

3. Ví dụ về Ứng dụng Cụ thể của Mô hình Decorator

Mô hình decorator có nhiều ứng dụng thực tế trong phát triển phần mềm, như:

  • Động thêm chức năng ghi log
  • Động thêm chức năng caching
  • Kiểm tra dữ liệu động

4. Triển khai của Mô hình Decorator trong Golang

4.1. Biểu đồ lớp UML

Mô hình Decorator trong Golang

4.2. Giới thiệu ví dụ

Trong ví dụ này, chúng ta có một giao diện Component và một lớp ConcreteComponent thực hiện phương thức Operation của giao diện Component.

Sau đó, chúng ta có một lớp Decorator, cũng thực hiện giao diện Component. Lớp Decorator có một biến thành viên kiểu Component.

Cả lớp ConcreteDecoratorA và ConcreteDecoratorB đều kế thừa từ lớp Decorator và thực hiện chức năng bổ sung bằng cách ghi đè phương thức Operation.

4.3. Bước 1 triển khai: Định nghĩa giao diện và lớp cụ thể

type Component interface {
	Operation() string
}

type ConcreteComponent struct {}

func (c *ConcreteComponent) Operation() string {
	return "hoạt động cụ thể của thành phần"
}

4.4. Bước 2 triển khai: Định nghĩa decorator

type Decorator struct {
	component Component
}

func (d *Decorator) Operation() string {
	return d.component.Operation()
}

4.5. Bước 3 triển khai: Triển khai của decorator

type ConcreteDecoratorA struct {
	Decorator
	addedState string
}

func (c *ConcreteDecoratorA) Operation() string {
	c.addedState = "Trạng thái mới"
	return c.addedState + " " + c.component.Operation()
}

type ConcreteDecoratorB struct {
	Decorator
}

func (c *ConcreteDecoratorB) Operation() string {
	return "hoạt động của decorator B cụ thể " + c.component.Operation()
}

4.6. Bước 4 triển khai: Sử dụng decorator

func main() {
	component := &ConcreteComponent{}

	decoratorA := &ConcreteDecoratorA{}
	decoratorA.component = component

	decoratorB := &ConcreteDecoratorB{}
	decoratorB.component = decoratorA

	result := decoratorB.Operation()
	fmt.Println(result)
}

5. So sánh Mô hình Decorator với Các Mô hình Thiết kế Khác

5.1. So sánh với Kế thừa

So với kế thừa, mô hình decorator có thể động thêm chức năng mà không cần sửa đổi mã nguồn hiện tại, trong khi kế thừa là cố định và cần phải xác định tại thời điểm biên dịch.

5.2. So sánh với Mô hình Proxy Tĩnh

Mô hình decorator và mô hình proxy tĩnh đều có thể mở rộng chức năng, nhưng mô hình decorator linh hoạt hơn và cho phép thêm và loại bỏ chức năng một cách linh động.

5.3. So sánh với Mô hình Proxy Động

Cả mô hình decorator và mô hình proxy động đều có thể mở rộng chức năng của đối tượng tại thời điểm chạy. Tuy nhiên, mô hình decorator trang trí một đối tượng duy nhất, trong khi mô hình proxy động liên quan đến việc truy cập gián tiếp giữa đối tượng proxy và đối tượng mục tiêu.