- vừa được xem lúc

Golang Design Patterns - Bridge. Tách bạch abstraction và implementation

0 0 27

Người đăng: Kha Leo

Theo Viblo Asia

Bridge là một mẫu thiết kế gây khó hiểu hơn so với các mẫu thiết kế ở những series trước. Theo cuốn sách nguyên bản của cuốn sách Gang of Four: "decouple an abstraction from its implementation so that the two can vary independently", khác hoàn toàn với việc luôn cố gắng đưa về abstraction trong các mẫu thiết kế chúng ta từng biết. Cùng tìm hiểu sâu hơn về mẫu thiết kế này nhé. image.png

Sơ đồ lớp mẫu thiết kế Bridge

I. Bridge - Structural Pattern

Rõ hơn một chút, Bridge tách một abstraction (thứ mà hầu hết các design pattern khác đưa về) hay một đối tượng ra khỏi implementations của nó. Bằng cách này, chúng ta có thể khiến một đối tượng làm bất cứ những gì chúng ta muốn, hay thay đổi một đối tượng trừu tượng nhưng vẫn sử dụng lại được những implementations của nó.

II. Bridge mang lại cho developers những gì?

Dễ thấy nhất đó là sự linh động mà mẫu thiết kế này mang lại đối với những đối tượng, struct thường xuyên có sự cập nhật, thêm mới. Cũng không hề có sự ràng buộc khi thay đổi code giữa 2 phía định nghĩa đối tượng và triển khai.

III. Ví dụ thực tế

Lấy ví dụ thực tế với trường hợp chúng ta cần triển khai một hệ thống quản lý in ấn, bao gồm 2 đối tượng chính là máy tính và máy in. Mặc định với máy tính ta có 2 đối tượng MacOS và Window, với máy in là Canon, ta có thể triển khai các đối tượng sau: MacOSCanon và WindowCanon. Mỗi đối tượng đều có phương thức Print, in ra thông tin máy tính và máy in hiện tại đang dùng.

Trường hợp bổ sung thêm loại máy in Epson, ta sẽ cần bổ sung thêm 2 đối tượng MacOSEpson và WindowEpson, với toàn bộ các phương thức mà MacOSCanon hay WindowCanon có thể làm.

Có thể thấy, với số lượng X máy tính và Y máy in, thì các đối tượng ta phải triển khai là X*Y, rất nhiều đúng không.

Đây chính là lúc mà Bridge nhảy vào để xử lý vấn đề trên. Như mình nói ở đầu bài, các để ghi nhớ bản chất của Bridge là: tách bạch abstractionimplementation. Ứng dụng vào ví dụ, thì máy tính được xem như là abstraction, còn máy in là implementation. Hai đối tượng này giao tiếp với nhau thông qua Bridge, nơi mà những abstraction (máy tính) chứa tham chiếu đến implementation (máy in).

Một ví dụ khá hài hước về Bridge rất dễ nhớ mà mình sưu tầm từ trang của Guru: image.png

IV. Implementation

Các đối tượng máy in luôn có phương thức Print, ta cần định nghĩa nó đầu tiên, thông qua interface Printer

package bridge type Printer interface { Print() error
} 

Tiếp đến, định nghĩa các Printer HP và Epson tương ứng dựa trên interface Printer như sau:

package bridge import "fmt" type HP struct {
} func (p *HP) Print() error { fmt.Println("HP printer printing...") return nil
}
package bridge import "fmt" type Epson struct {
} func (p *Epson) Print() error { fmt.Println("Epson printer printing...") return nil
}

Đã xong phần định nghĩa phần Implementation, bây giờ đến mục định nghĩa phần Abstraction, bắt đầu với Computer:

package bridge type Computer interface { Print() error SetPrinter(printer Printer)
}

Như mình có nói ở trên, abstraction sẽ chứa tham chiếu đến máy in, chính vì thế các computer luôn chứa instance của máy in, phương thức SetPrinter như một cách linh động để chúng ta thay đổi máy in mà đối tượng máy tính sử dụng:

package bridge import "fmt" type Window struct { printer Printer
} func (w *Window) Print() error { fmt.Println("Window printing...") return w.printer.Print()
} func (w *Window) SetPrinter(printer Printer) { w.printer = printer
}
package bridge import "fmt" type MacOS struct { printer Printer
} func (m *MacOS) Print() error { fmt.Println("MacOS printing...") return m.printer.Print()
} func (m *MacOS) SetPrinter(printer Printer) { m.printer = printer
}

Chạy chương trình trên:

	/* Example Bridge */ fmt.Println("*** Example Bridge ***") window := bridge.Window{} macOS := bridge.MacOS{} epson := bridge.Epson{} hp := bridge.HP{} window.SetPrinter(&epson) window.Print() macOS.SetPrinter(&hp) macOS.Print() fmt.Print("*** End of Bridge ***\n\n\n")

Với kết quả: image.png

Mình đã đưa ra một ví dụ ở mức cơ bản nhất để mọi người có cái nhìn trực quan nhất về mẫu thiết kế Bridge. Chúng ta sẽ không bị vướng bận khi xoá đi một trong các đối tượng máy in hay máy tính, hay không phải đối mặt với công việc định nghĩa lặp đi lặp lại khi thêm một loại máy tính hay máy in chẳng hạn.

V. Lời kết

Không phải lúc nào gặp vấn đề như trên chúng ta luôn dùng mẫu Bridge để giải quyết bài toán, mọi người có thể sử dụng mẫu thiết Factory mà mình từng để cập chẳng hạn, hoặc là...không sử dụng bất kỳ mẫu thiết kế nào nếu bài toán không quá phức tạp về số lượng đối tượng. Tất cả là tuỳ thuộc vào bạn 😄

Cảm ơn các bạn đã xem bài viết.

VI. References

  • Go Design Patterns (Mario Castro Contreras)
  • Guru

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 131

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 56

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 60

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 237

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 75

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 54