1. Mô hình Chain of Responsibility là gì

Mô hình Chain of Responsibility là một mô hình thiết kế hành vi giúp tách rời người gửi và người nhận yêu cầu, cho phép nhiều đối tượng có cơ hội xử lý yêu cầu. Mỗi người nhận chứa một tham chiếu đến một người nhận khác và nếu không thể xử lý yêu cầu, nó sẽ chuyển tiếp yêu cầu đến người nhận tiếp theo cho đến khi yêu cầu được xử lý hoặc đến cuối chuỗi.

2. Đặc điểm và Ưu điểm của mô hình Chain of Responsibility

Các đặc điểm và ưu điểm của mô hình Chain of Responsibility như sau:

  • Tách rời người gửi và người nhận: Người gửi không cần quan tâm về người nhận nào xử lý yêu cầu, cũng như không cần biết các bộ xử lý cụ thể trong chuỗi.
  • Linh hoạt: Nó cho phép thêm, loại bỏ hoặc sắp xếp động các bộ xử lý trong chuỗi mà không cần sửa đổi mã của người gửi và người nhận.
  • Mở rộng: Dễ dàng mở rộng chuỗi trách nhiệm bằng cách thêm các bộ xử lý cụ thể mới.
  • Nguyên lý Trách nhiệm Đơn: Mỗi bộ xử lý cụ thể chỉ quan tâm đến logic xử lý của chính nó.
  • Cấu hình: Chuỗi các bộ xử lý có thể được cấu hình theo nhu cầu, cho phép các yêu cầu khác nhau có các chuỗi xử lý khác nhau.

3. Ví dụ về Ứng dụng Thực tế của mô hình Chain of Responsibility

Mô hình Chain of Responsibility có nhiều ứng dụng thực tế, như:

  • Xử lý yêu cầu trong ứng dụng web: Nó có thể được sử dụng để xử lý các loại yêu cầu khác nhau, chẳng hạn như xác thực danh tính, đăng nhập và xác minh quyền.
  • Xử lý lỗi: Nó có thể được sử dụng để xử lý lỗi, với mỗi bộ xử lý chịu trách nhiệm xử lý một loại lỗi cụ thể và chuyển tiếp lỗi đến bộ xử lý tiếp theo khi cần thiết.
  • Xử lý sự kiện: Nó có thể được sử dụng để xử lý các loại sự kiện khác nhau, chẳng hạn như sự kiện nhấp chuột của người dùng, sự kiện yêu cầu mạng, và vân vân.

4. Triển khai mô hình Chain of Responsibility trong Golang

4.1 Sơ đồ lớp UML

Golang Chain of Responsibility Pattern

4.2 Giới thiệu Ví dụ

Trong sơ đồ lớp UML trên, chúng ta đã định nghĩa một trình xử lý trừu tượng (Handler) và hai trình xử lý cụ thể (ConcreteHandler1 và ConcreteHandler2). Người dùng (Client) khởi tạo yêu cầu bằng cách gọi phương thức handleRequest của trình xử lý.

4.3 Bước Triển khai 1: Định nghĩa Giao diện Trình xử lý Trừu tượng

type Handler interface {
    HandleRequest(request Request) error
    SetNext(handler Handler)
}

type Request interface {
    Condition bool
}

Giao diện trình xử lý trừu tượng định nghĩa phương thức HandleRequest để xử lý yêu cầu và phương thức SetNext để thiết lập trình xử lý kế tiếp.

4.4 Bước Triển khai 2: Triển khai Các Lớp Trình xử lý Cụ Thể

type ConcreteHandler1 struct {
    next Handler
}

func (h *ConcreteHandler1) HandleRequest(request Request) error {
    // Logic để xử lý yêu cầu
    if request.Condition {
        // Mã để xử lý yêu cầu
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("Không tìm thấy trình xử lý")
    }
}

func (h *ConcreteHandler1) SetNext(handler Handler) {
    h.next = handler
}

type ConcreteHandler2 struct {
    next Handler
}

func (h *ConcreteHandler2) HandleRequest(request Request) error {
    // Logic để xử lý yêu cầu
    if request.Condition {
        // Mã để xử lý yêu cầu
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("Không tìm thấy trình xử lý")
    }
}

func (h *ConcreteHandler2) SetNext(handler Handler) {
    h.next = handler
}

Các lớp trình xử lý cụ thể triển khai giao diện trình xử lý trừu tượng và ghi đè phương thức HandleRequest và SetNext.

4.5 Bước Triển khai 3: Xây dựng Chuỗi Trách nhiệm

handler1 := &ConcreteHandler1{}
handler2 := &ConcreteHandler2{}

handler1.SetNext(handler2)

Bằng cách khởi tạo các trình xử lý cụ thể và thiết lập trình xử lý kế tiếp, một chuỗi trách nhiệm được xây dựng.

4.6 Bước Triển khai 4: Mã Người Dùng

func main() {
    handler := &ConcreteHandler1{}

    // Xây dựng chuỗi trách nhiệm
    handler.SetNext(&ConcreteHandler2{})

    // Gửi yêu cầu
    handler.HandleRequest(Request{Condition: true})
}

Trong mã người dùng, một trình xử lý cụ thể được khởi tạo, trình xử lý kế tiếp được thiết lập, và sau đó phương thức HandleRequest được gọi để gửi một yêu cầu.