Showing preview only (376K chars total). Download the full file or copy to clipboard to get everything.
Repository: Ren0503/design-pattern
Branch: master
Commit: c87e0416d1fc
Files: 27
Total size: 287.9 KB
Directory structure:
gitextract_jadc42aa/
├── README.md
├── _config.yml
├── behavioral-pattern/
│ ├── README.md
│ ├── chain-of-responsibility/
│ │ └── README.md
│ ├── command/
│ │ └── README.md
│ ├── iterator/
│ │ └── README.md
│ ├── mediator/
│ │ └── README.md
│ ├── memento/
│ │ └── README.md
│ ├── observer/
│ │ └── README.md
│ ├── state/
│ │ └── README.md
│ ├── strategy/
│ │ └── README.md
│ ├── template-method/
│ │ └── README.md
│ └── visitor/
│ └── README.md
├── creational-pattern/
│ ├── README.md
│ ├── abstract-factory/
│ │ └── README.md
│ ├── builder/
│ │ └── README.md
│ ├── factory-method/
│ │ └── README.md
│ ├── prototype/
│ │ └── README.md
│ └── singleton/
│ └── README.md
└── structural-pattern/
├── README.md
├── adapter/
│ └── README.md
├── bridge/
│ └── README.md
├── composite/
│ └── README.md
├── decorator/
│ └── README.md
├── facade/
│ └── README.md
├── flyweight/
│ └── README.md
└── proxy/
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# DESIGN PATTERN LÀ GÌ ?

Design Pattern là một giải pháp tổng thể cho các vấn đề chung trong thiết kế phần mềm. Nó cũng tương tự các bản thiết kế cho xây dựng nhà cửa, chúng được dùng để giải quyết các vấn đề lặp đi lặp lại trong thiết kế của bạn.
Các design pattern không thể copy rồi paste như cách bạn làm với các function có sẵn hay thư viện, vì chúng không phải là những đoạn code cụ thể. Design pattern ở đây là những khái niệm tổng quát để giải quyết các vấn đề riêng biệt. Bạn có thể tìm hiểu các design pattern và triển khai chúng lên ứng dụng của bạn. Các pattern thường bị nhầm lẫn với thuật toán, vì chúng đều là những khái niệm mô tả giải pháp cho một vấn đề nào đó.
Trong khi thuật toán là định nghĩa những hành động cụ thể để giải quyết vấn đề thì design pattern lại là một mô tả cao hơn cho các giải pháp. Code cho cùng một pattern có thể được triển khai trên hai ứng dụng khác nhau.
## Tài liệu design pattern bao gồm những gì ?
Hầu hết các tài liệu mô tả rất chính thống, để cho mọi người có thể tái sử dụng cho nhiều trường hợp. Dưới đây là các thành phần thường có trong các document mô tả pattern:
- **Invention**: mục đích pattern, mô tả ngắn gọn cả vấn đề và giải pháp.
- **Motivation**: giải thích thêm vấn đề và giải pháp mà mô hình khả thi.
- **Structure**: cấu trúc của các lớp cho thấy từng phần của pattern và chúng có liên quan như thế nào.
- **Example**: ví dụ bằng một trong những ngôn ngữ lập trình phổ biến giúp bạn dễ dàng nắm bắt ý tưởng đằng sau pattern.
# Tại sao nên học design pattern
Sự thật là các lập trình viên có thể xoay xở làm việc trong nhiều năm mà không cần biết đến bất kỳ pattern nào. Rất nhiều người làm như vậy. Tuy nhiên, ngay cả trong trường hợp đó, bạn có thể đang triển khai một số pattern mà không hề hay biết. Vậy tại sao bạn lại dành thời gian tìm hiểu chúng?
- Giúp sản phẩm của chúng ta linh hoạt, dễ dàng thay đổi và bảo trì hơn.
- Có một điều luôn xảy ra trong phát triển phần mềm, đó là sự thay đổi về yêu cầu. Lúc này hệ thống phình to, các tính năng mới được thêm vào trong khi performance cần được tối ưu hơn.
- Design pattern cung cấp những giải pháp đã được tối ưu hóa, đã được kiểm chứng để giải quyết các vấn đề trong software engineering. Các giải pháp ở dạng tổng quát, giúp tăng tốc độ phát triển phần mềm bằng cách đưa ra các mô hình test, mô hình phát triển đã qua kiểm nghiệm.
- Những khi bạn gặp bất kỳ khó khăn đối với những vấn đề đã được giải quyết rồi, design patterns là hướng đi giúp bạn giải quyết vấn đề thay vì tự tìm kiếm giải pháp tốn kém thời gian.
- Giúp cho các lập trình viên có thể hiểu code của người khác một cách nhanh chóng (có thể hiểu là các mối quan hệ giữa các module chẳng hạn). Mọi thành viên trong team có thể dễ dàng trao đổi với nhau để cùng xây dựng dự án mà không tốn nhiều thời gian.
# Khi nào nên sử dụng design pattern
Việc sử dụng các design pattern sẽ giúp chúng ta giảm được thời gian và công sức suy nghĩ ra các cách giải quyết cho những vấn đề đã có lời giải. Lợi ích của việc sử dụng các mô hình Design Pattern vào phần mềm đó chính là giúp chương trình chạy uyển chuyển hơn, dễ dàng quản lý tiến trình hoạt động, dễ nâng cấp bảo trì, …
Tuy nhiên điểm bất cập của design pattern là nó luôn là một lĩnh vực khá khó nhằn và hơi trừu tượng. Khi bạn viết code mới từ đầu, khá dễ dàng để nhận ra sự cần thiết phải có design pattern. Tuy nhiên, việc áp dụng design pattern cho code cũ thì khó khăn hơn.
Khi sử dụng những design pattern có sẵn thì chúng ta sẽ đối mặt với một vấn đề nữa là perfomance của product (code sẽ chạy chậm chẳng hạn). Cần phải chắc chắn là bạn đã hiểu toàn bộ mã nguồn làm việc như thế nào trước khi đụng vào nó. Việc này có thể là dễ dàng hoặc là đau đầu, phụ thuộc vào độ phức tạp của code.
Hiện nay chúng ta đang áp dụng rất nhiều design pattern vào công việc lập trình của mình. Nếu bạn thường tải và cài đặt các thư viện, packages hoặc module nào đó thì đó là lúc bạn thực thi một design pattern vào hệ thống.
Tất cả các framework cho ứng dụng web như Laravel, Codeigniter… đều có sử dụng những kiến trúc design pattern có sẵn và mỗi framework sẽ có những kiểu design pattern riêng.
# Phân loại design pattern
Hệ thống các design pattern được chia thành 3 nhóm: nhóm Creational, nhóm Structural và nhóm Behavioral.
- [**Creational Pattern**](./creational-pattern) cung cấp các cơ chế tạo đối tượng để tăng tính linh hoạt và tái sử dụng mã hiện có.
+ [**Factory Method**](./creational-pattern/factory-method)
+ [**Abstract Factory**](./creational-pattern/abstract-factory)
+ [**Builder**](./creational-pattern/builder)
+ [**Prototype**](./creational-pattern/prototype)
+ [**Singleton**](./creational-pattern/singleton)
- [**Structural Pattern**](./structural-pattern) giải thích cách tập hợp các đối tượng và lớp thành các cấu trúc lớn hơn, trong khi vẫn giữ cho cấu trúc linh hoạt và hiệu quả.
+ [**Adapter**](./structural-pattern/adapter)
+ [**Bridge**](./structural-pattern/bridge)
+ [**Composite**](./structural-pattern/composite)
+ [**Decorator**](./structural-pattern/decorator)
+ [**Facade**](./structural-pattern/facade)
+ [**Flyweight**](./structural-pattern/flyweight)
+ [**Proxy**](./structural-pattern/proxy)
- [**Behavioral Pattern**](./behavioral-pattern) quan tâm đến việc giao tiếp hiệu quả và phân công nhiệm vụ giữa các đối tượng.
+ [**Chain Of Responsibility**](./behavioral-pattern/chain-of-responsibility)
+ [**Command**](./behavioral-pattern/command)
+ [**Iterator**](./behavioral-pattern/iterator)
+ [**Mediator**](./behavioral-pattern/mediator)
+ [**Memento**](./behavioral-pattern/memento)
+ [**Observer**](./behavioral-pattern/observer)
+ [**State**](./behavioral-pattern/state)
+ [**Strategy**](./behavioral-pattern/strategy)
+ [**Template Method**](./behavioral-pattern/template-method)
+ [**Visitor**](./behavioral-pattern/visitor)
# Code Example
Code ví dụ của RefactoringGuru
| | Ngôn ngữ | Source Code |
|-|----------|-------------|
|| C# | https://github.com/RefactoringGuru/design-patterns-csharp |
|| C++ | https://github.com/RefactoringGuru/design-patterns-cpp |
|| GO | https://github.com/RefactoringGuru/design-patterns-go |
|| JAVA | https://github.com/RefactoringGuru/design-patterns-java |
|| PHP | https://github.com/RefactoringGuru/design-patterns-php |
|| PYTHON | https://github.com/RefactoringGuru/design-patterns-python |
|| RUBY | https://github.com/RefactoringGuru/design-patterns-ruby |
|| SWIFT | https://github.com/RefactoringGuru/design-patterns-swift |
|| TYPESCRIPT | https://github.com/RefactoringGuru/design-patterns-typescript |
# Nguồn
## Sách

## Tác giả: [Refactoring.Guru](https://refactoring.guru)

================================================
FILE: _config.yml
================================================
theme: jekyll-theme-tactile
================================================
FILE: behavioral-pattern/README.md
================================================
# Behavioral Design Pattern
Behavioral Pattern quan tâm đến việc giao tiếp hiệu quả và phân công nhiệm vụ giữa các đối tượng.
## Chain of Responsibility
[](./chain-of-responsibility)
Cho phép bạn truyền các yêu cầu dọc theo một chuỗi xử lý. Khi nhận được yêu cầu, mỗi trình xử lý sẽ quyết định xử lý yêu cầu hoặc truyền nó cho trình xử lý tiếp theo trong chuỗi.
## Command
[](./command)
Biến một yêu cầu thành một đối tượng độc lập bao gồm tất cả thông tin của yêu cầu đó. Chuyển đổi này giúp bạn truyền các yêu cầu dưới dạng tham số của phương thức, trì hoãn hoặc chờ đợi việc thực thi một yêu cầu hay hỗ trợ các hoạt động hoàn tác.
## Iterator
[](./iterator)
Duyệt phần tử của một tập hợp mà không để lộ dạng cơ bản của nó (danh sách, ngăn xếp, cây, ...)
## Mediator
[](./mediator)
Giúp bạn giảm các phụ thuộc hỗn tạp giữa các đối tượng. Pattern hạn chế các giao tiếp trực tiếp giữa các đối tượng và buộc nó giao tiếp thông qua đối tượng mediator.
## Memento
[](./memento)
Lưu và phục hồi trạng thái trước đó của một đối tượng mà không để lộ chi tiết triển khai của nó
## Observer
[](./observer)
Giúp bạn định nghĩa một cơ chế đăng ký để thông báo cho nhiều đối tượng về bất kỳ sự kiện nào diễn ra với đối tượng mà chúng đang quan sát.
## State
[](./state)
Chỉnh sửa hành vi của một đối tượng khi trạng thái bên trong nó thay đổi. Nó xảy ra nếu như một đối tượng thay đổi lớp của nó.
## Strategy
[](./strategy)
Giúp bạn xác định một nhóm thuật toán, đặt chúng vào một lớp riêng biệt và làm cho các đối tượng của chúng có thể hoán đổi lẫn nhau.
## Template Method
[](./template-method)
Định nghĩa bộ khung của thuật toán ở lớp cha (superclass) nhưng các lớp con (subsclasses) có thể ghi đè lên các bước cụ thể của thuật toán mà không làm thay đổi cấu trúc của nó.
## Visitor
[](./visitor)
Tách các thuật toán khỏi đối tượng mà chúng đang hoạt động trên đó.
================================================
FILE: behavioral-pattern/chain-of-responsibility/README.md
================================================
# Chain of Responsibility
## 📜 Mục đích
**Chain of Responsibility** là một design pattern trong nhóm behavioral cho phép bạn truyền các yêu cầu dọc theo một chuỗi xử lý. Khi nhận được yêu cầu, mỗi trình xử lý sẽ quyết định xử lý yêu cầu hoặc truyền nó cho trình xử lý tiếp theo trong chuỗi.

## 😟 Vấn đề
Tưởng tượng bạn đang làm việc với hệ thống đặt hàng trực tuyến. Bạn muốn giới hạn truy cập đến hệ thống để chỉ những người dùng đã xác thực mới có thể đặt đơn hàng. Còn người quản trị viên (admin) có thể truy cập đến tất cả đơn hàng.
Sau khi lên kế hoạch, bạn nhận ra là các trình kiểm tra(check) phải làm việc liên tục. Vì ứng dụng có thể phải xác thực người dùng bất cứ khi nào hệ thống nhận về yêu cầu có kèm theo chứng thư của người dùng. Tuy nhiên, nếu chứng thư không hợp lệ và việc xác thực thất bại, thì sẽ không có bất kỳ trình kiểm tra nào khác xử lý nó.

Trong nhiều tháng tiếp theo, bạn đã phải triển khai rất nhiều các trình kiểm tra liên tục:
- Một người đồng nghiệp đề nghị rằng sẽ không an toàn khi truyền dữ liệu thuần thẳng đến hệ thống. Bạn cần thêm một bước xác nhận tính hợp lệ của dữ liệu trong yêu cầu.
- Sau đó, một ai đó nói rằng hệ thống của bạn dễ bị tấn công brute force để dò mật khẩu. Để tránh điều đó, bạn phải thêm một trình kiểm tra để lọc các yêu cầu thất bại lặp lại bởi cùng một địa chỉ IP.
- Tiếp đến bạn có thêm đề nghị là nên tăng tốc hệ thống bằng cách sử dụng kết quả từ bộ đệm với những yêu cầu lặp lại cùng một dữ liệu. Do đó, bạn phải thêm tiếp một trình kiểm tra khác để chỉ truyền các yêu cầu đến hệ thống khi nó không phù hợp với phản hồi từ cache.

Code cho trình kiểm tra của bạn đã lộn xộn, giờ đây nó còn tệ hơn lúc trước khi bạn thêm các tính năng mới. Thay đổi một trình kiểm tra thỉnh thoảng sẽ ảnh hưởng lên cả những cái khác. Và tệ hơn nữa là khi bạn muốn dùng lại trình kiểm tra cho các bộ phận khác trong hệ thống, bạn phải sao chép một phần code vì bộ phận đó chỉ yêu cầu vài trình kiểm tra chứ không phải tất cả.
Hệ thống sẽ trở nên rất khó hiểu và khó hơn để bảo trì. Sau nhiều ngày đấu tranh với code bạn quyết định refactor tất cả mọi thứ.
## 😊 Giải pháp
Giống như các behavioral khác, **Chain of Responsibility** dựa trên việc chuyển đổi các hành vi riêng biệt thành các đối tượng độc lập được gọi là **handlers**. Trong trường hợp này, mỗi trình kiểm tra sẽ mở rộng các lớp của nó với một phương thức đơn nhất thực hiện công việc kiểm tra. Yêu cầu và dữ liệu của nó, được truyền đến phương thức này như là một tham số.
Pattern gợi ý bạn liên kết các handler thành một chuỗi(chain). Mỗi handler được liên kết có một trường cho lưu trữ tham chiếu đến handler kế tiếp trong chuỗi. Thêm vào đó, để xử lý một yêu cầu, handler truyền yêu cầu đến xa hơn theo chuỗi. Yêu cầu sẽ chạy khắp chuỗi cho đến khi tất cả handler có cơ hội xử lý nó.
Điều quan trọng ở đây: handler có thể quyết định không truyền yêu cầu sâu hơn trong chuỗi và dừng bất kỳ việc xử lý nào một cách hiệu quả.
Ở ví dụ với hệ thống đặt hàng, một handler thực hiện xử lý sau đó quyết định truyền yêu cầu sâu hơn. Giả định yêu cầu bao gồm dữ liệu hợp lệ, tất cả handler có thể thực thi hành vi chính của nó, cho dù đó là kiểm tra xác thực hay bộ nhớ đệm.

Tuy nhiên, có một cách tiếp cận khác nhẹ nhàng hơn (và chuẩn hơn), mỗi khi nhận được yêu cầu, một handler quyết định liệu nó có thể xử lý hay không. Nếu nó có thể, sẽ không phải truyền yêu cầu xa hơn. Thế nên, sẽ chỉ có một handler để xử lý yêu cầu hoặc không có cái nào cả. Cách tiếp cận này rất giống với xử lý sự kiện trong ngăn xếp phần tử ở giao diện đồ hoạ người dùng.
Ví dụ, khi người dùng click một button, sự kiện sẽ truyền đến chuỗi phần tử GUI, bắt đầu với button, tiếp đến là container(có thể là form hoặc panel) và kết thúc ở của sổ chính của ứng dụng. Sự kiện sẽ được xử lý ở phần tử đầu tiên trong chuỗi có thể xử lý nó. Ví dụ này đáng lưu tâm vì nó cho thấy một chuỗi có thể mở rộng từ một đối tượng cây.

Điều quan trọng là tất cả lớp handler phải triển khai cùng interface. Mỗi handler cụ thể chỉ nên quan tâm một thứ theo sau phương thức thực thi. Cách này giúp bạn có thể tạo chuỗi khi đang chạy, sử dụng handler khác nhau mà không cần ghép code với lớp cụ thể của nó.
## 🚗 Thế Giới Thực
Bạn vừa mua và cài đặt một vài phần cứng mới lên máy tính của bạn. Ví lý do cá nhân, nên máy tính bạn có nhiều hệ điều hành. Bạn thử boot tất cả và xem phần cứng có được hỗ trợ không. Window nhận ra nó và tự động enable phần cứng. Nhưng, Linux yêu dấu của bạn lại từ chối làm việc với phần cứng mới. Bất lực, bạn quyết định gọi đến số điện thoại hỗ trợ khi mua phần cứng.
Thứ đầu tiên mà bạn nghe là giọng robot phản hồi tự động. Nó đề nghị các giải pháp phổ biến với nhiều vấn đề khác nhau nhưng không cái nào liên quan đến trường hợp của bạn. Sau đấy, robot kết nối bạn với nhà điều hành trực tiếp.
Xui xẻo, nhà điều hành cũng không thể đề xuất được điều gì cụ thể. Anh ta cứ nói theo hướng dẫn sử dụng, và không chịu lắng nghe bạn. Sau khi nghe: "bạn đã thử tắt máy và bật lại chưa" khoảng 10 lần, bạn đề nghi kết nối đến kỹ sư thích hợp.
Sau cùng, nhà điều hành chuyển cuộc gọi của bạn đến kỹ sư, một người có lẽ khao khát được nói chuyện trực tiếp với con người hàng giờ khi anh ta ngồi cô đơn trong phòng server ở một hầm tối nào đó trong toà nhà nào đó. Kỹ sư nói với bạn nơi tải về drive thích hợp cho phần cứng của bạn và cách cài đặt nó trên Linux. Cuối cùng vấn đề được giải quyết.

## 🏢 Cấu trúc

1. **Handler** khai báo interface chung cho tất cả concrete handler. Nó thường chỉ bao gồm một phương thức đơn nhất cho tất cả yêu cầu xử lý, nhưng thỉnh thoảng nó có thể chứa phương thức khác cho cài đặt handler tiếp theo trong chuỗi.
2. **Base Handler** là lớp tuỳ chọn, nơi bạn có thể đặt code mẫu vào tất cả lớp handler.
Thông thường, lớp này định nghĩa một trường lưu trữ tham chiếu đến handler kế tiếp. Client có thể tạo chuỗi bằng cách truyền handler đến hàm khởi tạo hoặc setter của handler trước đó.
Lớp còn có thể triển khai các xử lý mặc định: nó có thể truyền thực thi sang handler tiếp theo sau khi kiểm tra sự tồn tại của nó.
3. **Concrete Handler** bao gồm đoạn code thực cho yêu cầu xử lý. Khi nhận yêu cầu, mỗi handler phải quyết định xử lý nó hoặc truyền nó dọc theo chuỗi.
Handler thường là khép kín và bất biến, nhận mỗi dữ liệu cần thiết chỉ một lần thông qua hàm khởi tạo.
4. **Client** có thể tạo chuỗi chỉ một lần hoặc tạo động, dựa trên logic của ứng dụng. Lưu ý yêu cầu có thể được gửi đến bất kỳ handler nào trong chuỗi, không nhất thiết phải là đầu tiên.
## 👨💻 Mã giả
Trong ví dụ này, Chain of Responsibility chịu trách nhiệm hiển thị thông tin trợ giúp cho người dùng theo ngữ cảnh ở các phần tử GUI đang hoạt động.

Ứng dụng GUI thường có cấu trúc là một đối tượng cây. Ví dụ, lớp `Dialog`, thứ sẽ hiển thị cửa sổ chính của ứng dụng, sẽ là *root* của đối tượng cây. Dialog bao gồm `Panels`, sẽ chứa những panel khác hoặc phần tử đơn giản hơn như `Button` hay `TextFields`.
Một phần tử đơn giản có thể hiển thị `tooltips` theo ngữ cảnh dễ dàng, miễn là thành phần đó có một số văn bản trợ giúp được chỉ định. Nhưng các thành phần phức tạp hơn xác định cách riêng của chúng để hiển thị trợ giúp theo ngữ cảnh, chẳng hạn như hiển thị đoạn trích từ sách hướng dẫn hoặc mở trong trình duyệt.

Khi người dùng click vào một phần tử và nhấn phím `F1`, ứng dụng sẽ xác định thành phần được click và gửi yêu cầu trợ giúp. Yêu cầu chạy qua tất cả các container của phần tử cho đến khi đến được phần tử có khả năng hiển thị thông tin trợ giúp.
```c
// Interface handler khai báo một phương thức cho tạo chuỗi
// handler. Nó còn khai báo một phương thức thực thi yêu cầu.
interface ComponentWithContextualHelp is
method showHelp()
// Lớp cơ sở cho các thành phần đơn giản.
abstract class Component implements ComponentWithContextualHelp is
field tooltipText: string
// Thành phần của container hành độn như một liên kết
// tiếp theo trong chuỗi handler.
protected field container: Container
// Thành phần hiển thị tooltip nếu nó có văn bản trợ giúp
// được chỉ định cho nó. Nếu không nó chuyển tiếp cuộc gọi
// đến container.
method showHelp() is
if (tooltipText != null)
// Hiển thị tooltip.
else
container.showHelp()
// Container có thể bao gồm thành phần đơn giản hoặc container khác.
// Chuỗi quan hệ được thiết lập ở đây. Lớp kế thừa hành vi `showHelp`
// từ cha của nó.
abstract class Container extends Component is
protected field children: array of Component
method add(child) is
children.add(child)
child.container = this
// Thành phần nguyên thuỷ có thể ổn với triển khai
// trợ giúp mặc định...
class Button extends Component is
// ...
// Nhưng với thành phần phức tạp, nó có thể ghi đè triển khai mặc
// định. Nếu văn bản trợ giúp không thể được cung cấp theo cách mới,
// thành phần có thể gọi triển khai cơ sở (xem lớp Component).
class Panel extends Container is
field modalHelpText: string
method showHelp() is
if (modalHelpText != null)
// Hiển thị cửa sổ modal với văn bản trợ giúp.
else
super.showHelp()
// ...giống như trên...
class Dialog extends Container is
field wikiPageURL: string
method showHelp() is
if (wikiPageURL != null)
// Hiển thị trang wiki trợ giúp.
else
super.showHelp()
// Code ở client.
class Application is
// Mọi ứng dụng cấu hình chuỗi khác nhau.
method createUI() is
dialog = new Dialog("Budget Reports")
dialog.wikiPageURL = "http://..."
panel = new Panel(0, 0, 400, 800)
panel.modalHelpText = "This panel does..."
ok = new Button(250, 760, 50, 20, "OK")
ok.tooltipText = "This is an OK button that..."
cancel = new Button(320, 760, 50, 20, "Cancel")
// ...
panel.add(ok)
panel.add(cancel)
dialog.add(panel)
// Hãy tưởng tượng điều gì xảy ra ở đây.
method onF1KeyPress() is
component = this.getComponentAtMouseCoords()
component.showHelp()
```
## 💡 Ứng dụng
**🐞 Sử dụng Chain of Responsibility khi chương trình của bạn phải xử lý các loại yêu cầu khác nhau bằng nhiều cách khác nhau, nhưng kiểu yêu cầu chính xác và trật tự của nó thì không biết trước.**
⚡ CoR giúp bạn liên kết nhiều handler thành một chuỗi và khi nhận yêu cầu, sẽ "hỏi" mỗi handler có thể xử lý nó không. Cách này giúp tất cả handler có cơ hội xử lý yêu cầu.
**🐞 Sử dụng CoR khi nó là thiết yếu để thực thi nhiều handler trong một trật tự cụ thể**
⚡ Vì bạn có thể liên kết các handler trong chuỗi theo bất kỳ thứ tự nào, tất cả yêu cầu có thể đi qua chuỗi theo chính xác những gì bạn định ra.
**🐞 Sử dụng CoR khi tập hợp handler và thứ tự của chúng thay đổi theo thời gian**
⚡ Nếu bạn cung cấp setter cho trường tham chiếu trong lớp handler, bạn có thể chèn, xoá hoặc thay đổi thứ tự handler.
## 📋 Triển khai
1. Khai báo interface handler và mô tả signature của một phương thức để xử lý các yêu cầu.
Quyết định cách client sẽ truyền dữ liệu yêu cầu vào phương thức. Cách linh hoạt nhất là chuyển yêu cầu thành một đối tượng và chuyển nó đến phương thức xử lý dưới dạng một tham số.
2. Để loại bỏ code mẫu trùng lặp trong concrete handler, cần tạo một lớp handler cơ sở trừu tượng, bắt nguồn từ interface handler.
Lớp này phải có một trường để lưu trữ một tham chiếu đến handler tiếp theo trong chuỗi. Xem xét việc làm cho lớp trở nên bất biến. Tuy nhiên, nếu bạn định sửa đổi chuỗi trong thời gian chạy, bạn cần xác định một setter để thay đổi giá trị của trường tham chiếu.
Bạn cũng có thể triển khai hành vi mặc định thuận tiện cho phương pháp xử lý, đó là chuyển tiếp yêu cầu đến đối tượng tiếp theo trừ khi không còn đối tượng nào. Các concrete handler có thể sử dụng hành vi này bằng cách gọi phương thức cha.
3. Từng cái một tạo các lớp con của concrete handler và thực hiện các phương pháp xử lý của chúng. Mỗi handler phải đưa ra hai quyết định khi nhận được yêu cầu:
- Liệu nó có xử lý yêu cầu hay không.
- Liệu nó có chuyển yêu cầu theo chuỗi hay không.
4. Client có thể tự lắp ráp chuỗi hoặc nhận chuỗi được tạo sẵn từ các đối tượng khác. Trong trường hợp sau, bạn phải triển khai một số lớp factory để xây dựng chuỗi theo cấu hình hoặc cài đặt môi trường.
5. Client có thể kích hoạt bất kỳ handler nào trong chuỗi, không chỉ handler đầu tiên. Yêu cầu sẽ được chuyển dọc theo chuỗi cho đến khi một số handler từ chối chuyển thêm hoặc cho đến khi nó đến cuối chuỗi.
6. Do tính chất động của chuỗi, client nên sẵn sàng xử lý các tình huống sau:
- Chuỗi có thể bao gồm một liên kết duy nhất.
- Một số yêu cầu có thể không đến cuối chuỗi.
- Những yêu cầu khác có thể đến cuối chuỗi không được xử lý.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn có thể kiểm soát thứ tự xử lý yêu cầu.
✔️ *Single Responsibility Principle*. Bạn có thể tách các lớp gọi hoạt động từ các lớp thực hiện hoạt động.
✔️ *Open/Closed Principle*. Bạn có thể thêm handler mới vào ứng dụng mà không ảnh hưởng đến code client hiện có.
### Nhược điểm
❌ Một số yêu cầu có thể không được giải quyết.
## 🔁 Quan hệ với các pattern khác
**Chain of Responsibility**, **Command**, **Mediator** và **Observer** giải quyết các cách khác nhau để kết nối người gửi và người nhận yêu cầu:
- **CoR** chuyển một yêu cầu tuần tự dọc theo một chuỗi động gồm những người nhận tiềm năng cho đến khi một trong số họ xử lý nó.
- **Command** thiết lập các kết nối một chiều giữa người gửi và người nhận.
- **Mediator** loại bỏ các kết nối trực tiếp giữa người gửi và người nhận, buộc họ phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- **Observer** cho phép người nhận đăng ký động và hủy đăng ký nhận yêu cầu.
**Chain of Responsibility** thường được sử dụng cùng với **Composite**. Trong trường hợp này, khi một thành phần leaf nhận được một yêu cầu, nó có thể chuyển nó qua chuỗi của tất cả các thành phần mẹ xuống gốc của cây đối tượng.
Handler trong **Chain of Responsibility** có thể triển khai như **Command**. Trong trường hợp này bạn có thể thực thi các hành động khác nhau trên cùng một đối tượng ngữ cảnh, được biểu diễn bởi yêu cầu.
Tuy nhiên, có cách tiếp cận khác, khi bản thân yêu cầu là một đối tượng **Command**. Trong trường hợp này bạn có thể thực thi cùng một hành động trên một loạt các ngữ cảnh khác nhau được liên kết thành một chuỗi.
**Chain of Responsibility** và **Decorator** có cấu trúc lớp rất giống nhau. Cả hai pattern đều dựa vào thành phần đệ quy để truyền việc thực thi qua một loạt các đối tượng. Tuy nhiên, có một số khác biệt quan trọng.
Các handler trong **CoR** có thể thực hiện các hoạt động tùy ý độc lập với nhau. Nó cũng có thể ngừng chuyển yêu cầu thêm vào bất kỳ lúc nào. Mặt khác, các **Decorator** khác nhau có thể mở rộng hành vi của đối tượng trong khi vẫn giữ cho nó nhất quán với interface cơ sở. Ngoài ra, **Decorator** không được phép phá vỡ quy trình của yêu cầu.
# Nguồn
[refactoring](https://refactoring.guru/design-patterns/chain-of-responsibility)
================================================
FILE: behavioral-pattern/command/README.md
================================================
# Command
## 📜 Mục đích
**Command** là một design pattern thuộc nhóm behavioral, nó biến một yêu cầu thành một đối tượng độc lập bao gồm tất cả thông tin của yêu cầu đó. Chuyển đổi này giúp bạn truyền các yêu cầu dưới dạng tham số của phương thức, trì hoãn hoặc chờ đợi việc thực thi một yêu cầu hay hỗ trợ các hoạt động hoàn tác.

## 😟 Vấn đề
Tưởng tượng bạn đang làm việc với một ứng dụng soạn thảo văn bản. Công việc hiện tại của bạn là tạo một thanh công cụ với nhóm button cho các thao tác khác nhau của editor. Bạn đã tạo một lớp `Button` gọn gàng để có thể dùng cho các button khác của thanh công cụ, cũng như cho các button chung ở các cửa sổ khác.

Trong khi tất cả button này trông giống nhau, thì chúng lại hỗ trợ những công việc khác nhau.
Vậy bạn sẽ đặt code cho các xử lý thao tác click khác nhau của chúng ở đâu ? Giải pháp đơn giản nhất là tạo hàng nghìn lớp con cho từng nơi mà button được sử dụng. Các lớp con này sẽ bao gồm code cho thực thi thao tác click.

Rất nhanh chóng, bạn nhận ra cách tiếp cận này tồn đọng rất nhiều thiếu sót. Đầu tiên, bạn sẽ có một số lượng rất lớn lớp con, và nó sẽ không ổn khi bạn sửa đổi lớp `Button` cơ sở vì bạn phải thay đổi tất cả các lớp con của nó. Nói một cách đơn giản, code GUI của bạn đã trở nên phụ thuộc một cách khó hiểu vào những đoạn code dễ thay đổi của logic nghiệp vụ.

Và phần tồi tệ hơn ở đây. Một vài thao tác như copy/paste, sẽ cần được gọi từ rất nhiều nơi. Ví dụ, người dùng có thể click vào button "Copy" trên thanh công cụ, hoặc thực hiện thông quan menu hay chỉ đơn giản là Ctrl+C trên bàn phím.
Ban đầu, khi ứng dụng của bạn chỉ có một thanh công cụ, có thể đặt việc triển khai các hoạt động khác nhau vào các lớp con của button. Nói cách khác, ta có code để sao chép văn bản bên trong lớp con `CopyButton`. Nhưng sau đó, khi bạn triển khai menu, lối tắt và những thứ khác, bạn phải sao chép code của thao tác trong nhiều lớp hoặc làm cho menu phụ thuộc vào các button, mọi thứ sẽ trở nên tệ hoặc tệ hơn nữa.
## 😊 Giải pháp
Một thiết kế phần mềm tốt thường dựa trên *nguyên tắc tách biệt các mối quan tâm*, điều này thường dẫn đến việc chia ứng dụng thành nhiều lớp. Ví dụ phổ biến nhất: một lớp cho giao diện người dùng đồ họa và một lớp khác cho logic nghiệp vụ. Lớp GUI chịu trách nhiệm hiển thị hình ảnh đẹp mắt trên màn hình, thu nhận bất kỳ đầu vào nào và hiển thị kết quả về những gì người dùng và ứng dụng đang làm. Tuy nhiên, khi cần làm điều gì đó quan trọng, như tính toán quỹ đạo của mặt trăng hoặc soạn báo cáo hàng năm, lớp GUI sẽ ủy quyền công việc cho lớp logic nghiệp vụ cơ bản.
Trong đoạn code, nó có thể trông như thế này: một đối tượng GUI gọi một phương thức của đối tượng logic nghiệp vụ, truyền cho nó một số tham số. Quá trình này thường được mô tả như một đối tượng gửi một yêu cầu khác.

Command gợi ý rằng các đối tượng GUI không nên gửi trực tiếp các yêu cầu này. Thay vào đó, bạn nên trích xuất tất cả các chi tiết yêu cầu, chẳng hạn như đối tượng được gọi, tên của phương thức và danh sách các đối số vào một lớp command riêng biệt với một phương thức kích hoạt yêu cầu này.
Các đối tượng command đóng vai trò là liên kết giữa các đối tượng GUI và logic nghiệp vụ khác nhau. Từ bây giờ, đối tượng GUI không cần biết đối tượng logic nghiệp vụ nào sẽ nhận được yêu cầu và cách xử lý yêu cầu. Đối tượng GUI chỉ cần kích hoạt command, nó sẽ xử lý tất cả các chi tiết.

Bước tiếp theo là làm cho các command của bạn triển khai cùng một interface. Thông thường nó chỉ có một phương thức thực thi duy nhất mà không cần tham số. Interface này cho phép bạn sử dụng các command khác nhau với cùng một người gửi yêu cầu mà không cần kết hợp nó với các lớp command cụ thể. Như vậy, giờ đây bạn có thể chuyển đổi các đối tượng command được liên kết với người gửi, hay thay đổi một cách hiệu quả hành vi của người gửi trong thời gian chạy.
Bạn có thể nhận thấy một phần còn thiếu của vấn đề, đó là các tham số yêu cầu. Một đối tượng GUI có thể đã cung cấp cho đối tượng lớp nghiệp vụ một số tham số. Vì phương thức thực thi của command không có bất kỳ tham số nào, như vậy chúng ta sẽ chuyển các chi tiết yêu cầu đến người nhận như thế nào? Hóa ra command phải được cấu hình trước với dữ liệu này hoặc có khả năng tự lấy nó.

Hãy quay lại trình soạn thảo văn bản. Sau khi áp dụng Command, ta không còn cần đến tất cả các lớp con của button đó để thực hiện các hành vi click chuột khác nhau. Chỉ cần đặt một trường vào lớp `Button` cơ sở là đủ để lưu trữ tham chiếu đến đối tượng command và làm cho button thực hiện command đó khi click chuột.
Bạn sẽ triển khai một loạt các lớp command cho mọi hoạt động có thể và liên kết chúng với các button cụ thể, tùy thuộc vào hành vi dự kiến của các button.
Các phần tử GUI khác, chẳng hạn như menu, lối tắt hoặc toàn bộ hộp thoại, có thể được thực hiện theo cách tương tự. Chúng sẽ được liên kết với một command được thực thi khi người dùng tương tác với phần tử GUI. Như bạn có thể đoán bây giờ, các phần tử liên quan đến các hoạt động giống nhau sẽ được liên kết với các command giống nhau, ngăn chặn bất kỳ sự trùng lặp code nào.
Kết quả là, các command trở thành một lớp trung gian thuận tiện giúp giảm sự ghép nối giữa GUI và các lớp logic nghiệp vụ. Và đó chỉ là một phần nhỏ trong số những lợi ích mà Command có thể mang lại!
## 🚗 Thế Giới Thực

Sau khi đi bộ qua thành phố, bạn đến một nhà hàng sang trọng và ngồi vào bàn bên cửa sổ. Một người phục vụ thân thiện tiếp cận bạn và nhận đơn đặt hàng của bạn, viết nó ra một tờ giấy. Người phục vụ đi vào bếp và dán thứ tự lên tường. Sau một thời gian, đơn đặt hàng được chuyển đến đầu bếp, người sẽ đọc và nấu bữa ăn cho phù hợp. Người đầu bếp đặt bữa ăn vào khay cùng với thứ tự. Người phục vụ lấy khay, kiểm tra thứ tự để đảm bảo mọi thứ đều như bạn muốn và mang mọi thứ đến bàn của bạn.
Trật tự trên giấy dùng như một command. Nó vẫn còn trong hàng đợi cho đến khi đầu bếp sẵn sàng phục vụ nó. Đơn đặt hàng chứa tất cả các thông tin liên quan cần thiết để nấu bữa ăn. Nó cho phép đầu bếp bắt đầu nấu ăn ngay lập tức thay vì chạy xung quanh để làm rõ chi tiết đơn đặt hàng trực tiếp từ bạn.
## 🏢 Cấu trúc

1. **Sender** (hay còn gọi là invoker) là lớp chịu trách nhiệm khởi tạo các yêu cầu. Lớp này phải có một trường để lưu trữ một tham chiếu đến một đối tượng command. Sender(người gửi) kích hoạt command đó thay vì gửi yêu cầu trực tiếp đến receiver(người nhận). Lưu ý rằng sender không chịu trách nhiệm tạo đối tượng command. Thông thường, nó nhận một command được tạo trước từ client thông qua phương thức khởi tạo.
2. **Command** là interface, thường khai báo một phương thức đơn nhất để thực hiện lệnh.
3. **Concrete Command** thực hiện nhiều loại yêu cầu khác nhau. Một command cụ thể không được phép tự thực hiện công việc, mà chỉ chuyển lệnh gọi đến một trong các đối tượng logic nghiệp vụ. Tuy nhiên, để đơn giản hóa code, các lớp này có thể được hợp nhất.
Các tham số cần thiết để thực thi một phương thức trên một đối tượng nhận có thể được khai báo dưới dạng các trường trong concrete command. Bạn có thể làm cho các đối tượng command trở nên bất biến bằng cách chỉ cho phép khởi tạo các trường này thông qua phương thức khởi tạo.
4. **Receiver** là lớp chứa một số logic nghiệp vụ. Hầu như bất kỳ đối tượng nào cũng có thể hoạt động như một receiver. Hầu hết các command chỉ xử lý các chi tiết về cách một yêu cầu được chuyển đến receiver, trong khi receiver phải tự thực hiện công việc thực tế.
5. **Client** tạo và cấu hình các đối tượng command cụ thể. Client phải chuyển tất cả các tham số yêu cầu, bao gồm cả sender, vào phương thức khởi tạo của command. Sau đó, command kết quả có thể được liên kết với một hoặc nhiều receiver.
## 👨💻 Mã giả
Trong ví dụ này, Command giúp bạn theo dõi lịch sử các thao tác thực thi và hoàn tác nó nếu cần thiết.

Command dẫn đến các thay đổi trạng thái của editor (sao chép, cắt, dán) sẽ tạo bản sao lưu trạng thái của editor trước khi thực thi một thao tác liên kết với command. Sau khi command thực thi, nó lưu vào lịch sử command(một ngăn xếp các đối tượng command) cùng với bản sao lưu trạng thái của editor tại thời điểm đó. Sau đó, nếu người dùng cần hoàn tác một hành động, ứng dụng có thể lấy command gần nhất từ lịch sử, đọc bản sao liên kết với trạng thái của editor và phục hồi nó.
Code client (phần tử GUI, lịch sử command) không phải ghép với lớp command cụ thể bởi vì nó hoạt động với command thông qua interface command. Cách tiếp cận này giúp bạn thêm command mới vào ứng dụng mà không ảnh hưởng gì đến code hiện có.
```c
// Lớp command cơ sở xác định interface chung cho tất cả
// concrete command.
abstract class Command is
protected field app: Application
protected field editor: Editor
protected field backup: text
constructor Command(app: Application, editor: Editor) is
this.app = app
this.editor = editor
// Tạo một bản sao lưu trạng thái editor.
method saveBackup() is
backup = editor.text
// Phục hồi trạng thái editor.
method undo() is
editor.text = backup
// Phương thức thực thi khai báo trừu tượng cho tất cả
// concrete command tạo các triển khai của riêng nó.
// Phương thức trả về true hoặc false tuỳ thuộc vào command
// có thay đổi trạng thái editor hay không.
abstract method execute()
// Concrete command ở đây.
class CopyCommand extends Command is
// Bản sao command không được lưu vào lịch sử vì nó
// không thay đổi trạng thái editor.
method execute() is
app.clipboard = editor.getSelection()
return false
class CutCommand extends Command is
// Command cut thay đổi trạng thái editor, do đó nó phải
// được lưu vào lịch sử. Và nó sẽ được lưu miễn là
// phương thức trả về true.
method execute() is
saveBackup()
app.clipboard = editor.getSelection()
editor.deleteSelection()
return true
class PasteCommand extends Command is
method execute() is
saveBackup()
editor.replaceSelection(app.clipboard)
return true
// Thao tác undo cũng là command.
class UndoCommand extends Command is
method execute() is
app.undo()
return false
// Lịch sử command chỉ là một ngăn xếp.
class CommandHistory is
private field history: array of Command
// Last in...
method push(c: Command) is
// Thêm command vào cuối của mảng lịch sử.
// ...first out
method pop():Command is
// Lấy command gần nhất khỏi lịch sử.
// Lớp editor thực hiện các thao tác thực. Nó hoạt động như
// một receiver: tất cả command uỷ thác thực thi cho phương
// thức của editor.
class Editor is
field text: string
method getSelection() is
// Trả về văn bản được chon.
method deleteSelection() is
// Xoá văn bản được chon.
method replaceSelection(text) is
// Chèn nội dung của clipboard vào vị trí hiện tại.
// Lóp ứng dụng thiết lập quan hệ đối tượng. Nó hành động như
// một sender: khi điều gì đó cần hoàn thành, nó tạo đối tượng
// command và thực thi nó.
class Application is
field clipboard: string
field editors: array of Editors
field activeEditor: Editor
field history: CommandHistory
// Đoạn code gán command cho các đối tượng UI
// có thể trông như thế này.
method createUI() is
// ...
copy = function() { executeCommand(
new CopyCommand(this, activeEditor)) }
copyButton.setCommand(copy)
shortcuts.onKeyPress("Ctrl+C", copy)
cut = function() { executeCommand(
new CutCommand(this, activeEditor)) }
cutButton.setCommand(cut)
shortcuts.onKeyPress("Ctrl+X", cut)
paste = function() { executeCommand(
new PasteCommand(this, activeEditor)) }
pasteButton.setCommand(paste)
shortcuts.onKeyPress("Ctrl+V", paste)
undo = function() { executeCommand(
new UndoCommand(this, activeEditor)) }
undoButton.setCommand(undo)
shortcuts.onKeyPress("Ctrl+Z", undo)
// Thực thi command và kiểm tra xem nó có phải thêm vào lịch sử
// hay không.
method executeCommand(command) is
if (command.execute)
history.push(command)
// Lấy command gần nhất khởi lịch sử và chạy phương thức undo.
// Lưu ý ta không biết lớp của command này. Nhưng ta không cần
// phải biết, vì command biết cách phải thực hiện hành động undo.
method undo() is
command = history.pop()
if (command != null)
command.undo()
```
## 💡 Ứng dụng
**🐞 Sử dụng Command khi bạn muốn tham số hoá đối tượng với thao tác**
⚡ Command có thể chuyển hoá một phương thức cụ thể thành một đối tượng độc lập. Thay đổi này mở ra nhiều công dụng hấp dẫn: bạn có thể truyền command như một tham số của phương thức, lưu trữ chúng trong các đối tượng khác, thay đổi command đã liên kết ngay khi đang chạy,...
Ví dụ: bạn đang phát triển một thành phần GUI như một menu ngữ cảnh, và bạn muốn người dùng của bản có thể cấu hình các phần của menu để kích hoạt thao tác khi người dùng click vào một mục.
**🐞 Sử dụng Command khi bạn muốn tạo hàng đợi các thao tác, lên lịch các thực thi của chúng hoặc thực thi chúng từ xa**
⚡ Như bất kỳ đối tượng nào khác, command có thể được serialized(chuyển hoá), có nghĩa là chuyển đổi từ một đối tượng thành một chuỗi có thể ghi vào file hay cơ sở dữ liệu. Sau đó, chuỗi có thể được phục hồi lại thành đối tượng command ban đầu. Do đó bạn có thể trì hoãn và lên lịch thực thi command. Với cùng cách đấy bạn có thể xếp hàng(queue), ghi nhật ký(log) hay gửi command qua mạng.
**🐞 Sử dụng Comment khi bạn muốn triển khai các thao tác nghịch đảo**.
⚡ Mặc dù có nhiều cách để thực hiện hoàn tác / làm lại, nhưng Command có lẽ là phổ biến nhất.
Để có thể hoàn tác các thao tác, bạn cần triển khai lịch sử của các hành động đã thực hiện. Lịch sử command là một ngăn xếp chứa tất cả các đối tượng command đã thực thi cùng với các bản sao lưu liên quan về trạng thái của ứng dụng.
Phương pháp này có hai nhược điểm. Đầu tiên, không dễ dàng để lưu trạng thái của ứng dụng vì một số trong số đó có thể là riêng tư. Vấn đề này có thể được giảm thiểu với pattern **Memento**.
Thứ hai, các bản sao lưu trạng thái có thể tiêu tốn khá nhiều RAM. Do đó, đôi khi bạn có thể sử dụng một cách triển khai thay thế: thay vì khôi phục trạng thái trong quá khứ, lệnh thực hiện thao tác nghịch đảo. Hoạt động ngược lại cũng có một cái giá: nó có thể khó hoặc thậm chí không thể thực hiện được.
## 📋 Triển khai
1. Khai báo interface command với phương thức thực thi đơn nhất.
2. Bắt đầu trích xuất yêu cầu vào lớp concrete command, triển khai từ interface command. Mỗi lớp phải có một tập hợp trường cho lưu trữ tham số yêu cầu cùng với tham chiếu đến đối tượng receiver. Tất cả giá trị này được khởi tạo thông qua hàm khởi tạo của command.
3. Xác định các lớp sẽ hành động như sender. Thêm trường lưu trữ command vào các lớp này. Sender sẽ giao tiếp với command của nó chỉ thông qua interface command. Sender thường không tạo đối tượng command cho nó, mà sẽ lấy chúng từ code client.
4. Thay đổi sender để chúng thực thi command thay vì gửi yêu cầu trực tiếp đến receiver.
5. Client nên khởi tạo đối tượng theo trật tự sau:
- Tạo receiver.
- Tạo command và liên kết với receiver nếu cần.
- Tạo sender và liên kết với command cụ thể.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Single Responsibility Principle*. Bạn có thể tách các lớp gọi các thao tác từ các lớp thực hiện các thao tác này.
✔️ *Open/Closed Principle*. Bạn có thể thêm command mới vào ứng dụng mà không ảnh hưởng đến code client hiện có.
✔️ Bạn có thể triển khai hoàn tác/làm lại(undo/redo).
✔️ Bạn có thể triển khai thực hiện trì hoãn các thao tác.
✔️ Bạn có thể lắp ghép một tập hợp các command đơn giản thành một tập hợp các command phức tạp
### Nhược điểm
❌ Code có thể trở nên phức tạp hơn vì bạn đang thêm một lớp hoàn toàn mới giữa sender và receiver.
## 🔁 Quan hệ với các pattern khác
**Chain of Responsibility**, **Command**, **Mediator** và **Observer** giải quyết các cách khác nhau để kết nối người gửi và người nhận yêu cầu:
- **CoR** chuyển một yêu cầu tuần tự dọc theo một chuỗi động gồm những người nhận tiềm năng cho đến khi một trong số họ xử lý nó.
- **Command** thiết lập các kết nối một chiều giữa người gửi và người nhận.
- **Mediator** loại bỏ các kết nối trực tiếp giữa người gửi và người nhận, buộc họ phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- **Observer** cho phép người nhận đăng ký động và hủy đăng ký nhận yêu cầu.
Handler trong **Chain of Responsibility** có thể triển khai như **Command**. Trong trường hợp này bạn có thể thực thi các hành động khác nhau trên cùng một đối tượng ngữ cảnh, được biểu diễn bởi yêu cầu.
Bạn có thể sử dụng **Command** và **Memento** cùng nhau khi thực hiện "hoàn tác". Trong trường hợp này, các command chịu trách nhiệm thực hiện các hoạt động khác nhau trên một đối tượng đích, trong khi các mementos lưu trạng thái của đối tượng đó ngay trước khi command được thực thi.
**Command** và **Strategy** có thể trông giống nhau vì bạn có thể sử dụng cả hai để tham số hóa một đối tượng bằng một số hành động. Tuy nhiên, chúng có mục đích rất khác nhau.
Bạn có thể sử dụng **Command** để chuyển đổi bất kỳ thao tác nào thành một đối tượng. Các tham số của thao tác trở thành các trường của đối tượng đó. Việc chuyển đổi cho phép bạn trì hoãn việc thực hiện thao tác, xếp hàng đợi, lưu trữ lịch sử lệnh, gửi lệnh đến các dịch vụ từ xa, v.v.
Mặt khác, **Strategy** thường mô tả các cách khác nhau để thực hiện cùng một việc, cho phép bạn hoán đổi các thuật toán này trong một lớp ngữ cảnh duy nhất.
**Prototype** có thể hữu ích khi bạn cần lưu các bản sao của **Command** vào lịch sử.
Bạn có thể coi **Visitor** như một phiên bản mạnh mẽ của **Command**. Các đối tượng của nó có thể thực thi các hoạt động trên các đối tượng khác nhau của các lớp khác nhau.
# Nguồn
[refactoring](https://refactoring.guru/design-patterns/command)
================================================
FILE: behavioral-pattern/iterator/README.md
================================================
# Iterator
## 📜 Mục đích
**Iterator** là một design pattern thuộc nhóm behavioral giúp bạn duyệt phần tử của một tập hợp mà không để lộ dạng cơ bản của nó (danh sách, ngăn xếp, cây, ...)

## 😟 Vấn đề
Collection(tập hợp) là một trong những kiểu dữ liệu được sử dụng nhiều nhất trong lập trình. Hiểu đơn giản nó chỉ là nơi chứa cho một nhóm đối tượng.

Phần lớn tập hợp lưu trữ phần tử của nó bằng các danh sách đơn giản. Tuy nhiên một số lại sử dụng ngăn xếp, cây, đồ thị hoặc một cấu trúc dữ liệu phức tạp nào khác.
Nhưng việc tập hợp được tạo như thế nào không quan trọng, nó chỉ cần cung cấp một số cách để các đoạn code khác có thể truy cập và sử dụng phần tử của nó. Thế nên cần có một phương pháp để duyệt qua từng phần tử của tập hợp và đảm bảo truy cập không trùng lặp tại bất kỳ phần tử nào.
Điều này nghe có vẻ dễ dàng nếu tập hợp của bạn dựa trên dạng danh sách. Bạn chỉ việc lặp lại tất cả phần tử.
Nhưng nếu nó là một cấu trúc dữ liệu phức tạp khác như cây thì sao? Ví dụ, hôm nay bạn phải thực hiện duyệt cây theo chiều sâu(depth-first traversal), nhưng ngày hôm sau bạn lại nhận yêu cầu là cần thêm duyệt cây theo chiều rộng(breadth-first traversal), và các ngày kế tiếp bạn phải thực hiện các công việc khác như truy cập ngẫu nhiên ba phần tử,...

*Một tập hợp có thể duyệt theo nhiều cách*
Việc thêm nhiều thuật toán duyệt vào tập hợp có thể làm mờ đi nhiệm vụ chính của nó, là lưu trữ dữ liệu hiệu quả. Thêm vào đó, một vài thuật toán chỉ phù hợp với vài ứng dụng cơ bản, thế nên thêm nó vào lớp tập hợp chung có thể sẽ không phù hợp.
Mặt khác, code client làm việc với nhiều tập hợp khác nhau thường không quan tâm đến chúng lưu trữ phần tử như thế nào. Tuy nhiên, vì tập hợp cung cấp các cách khác nhau để truy cập phần tử, nên bạn không có lựa chọn nào khác ngoài kết hợp code của bạn với lớp tập hợp cụ thể.
## 😊 Giải pháp
Ý tượng ở đây là mở rộng hành vi duyệt của một tập hợp thành một đối tượng riêng biệt gọi là *iterator*.

Ngoài việc triển khai thuật toán chính, một đối tượng iterator còn đóng gói tất cả các chi tiết duyệt, chẳng hạn như vị trí hiện tại và số phần tử còn lại của tập hợp. Do đó, nhiều iterator có thể đi qua cùng một một tập hợp cùng lúc, độc lập với nhau.
Thông thường, các iterator cung cấp một phương thức chính để tìm nạp các phần tử của tập hợp. Client có thể tiếp tục chạy phương thức này cho đến khi nó không trả về bất kỳ thứ gì, có nghĩa là iterator đã duyệt qua tất cả các phần tử.
Tất cả các iterator phải triển khai cùng một interface. Điều này làm cho code client tương thích với bất kỳ loại tập hợp nào hoặc bất kỳ thuật toán duyệt nào miễn là có một iterator thích hợp. Nếu bạn cần một cách đặc biệt để duyệt qua một tập hợp, bạn chỉ cần tạo một lớp iterator mới mà không cần phải thay đổi tập hợp hoặc ứng dụng client.
## 🚗 Thế Giới Thực

Bạn có kế hoạch đi thăm Roma trong vài ngày và tham quan tất cả địa điểm chính nổi bật và thu hút. Nhưng khi đến đó, bạn có thể lãng phí nhiều thời gian để tìm đường, thậm chí bạn còn không thể tìm được đấu trường La Mã(nơi thông với mọi con đường).
Mặt khác bạn mua một ứng dụng hướng dẫn cho smartphone của bạn và dùng nó để tìm đường. Nó rất thông minh và tiện lợi, bạn có thể đến bất kỳ nơi thú vị nào mà bạn muốn.
Bên cạnh đó bạn cũng có thể bỏ ra một phần tiền cho chuyến đi để mướn một người địa phương, người nắm mọi con đường của thành phố trong lòng bàn tay. Hướng dẫn viên này có thể điều chỉnh hướng đi theo ý thích của bạn, chỉ cho bạn mọi điểm tham quan và kể rất nhiều điển tích thú vị. Điều đó sẽ tuyệt vời hơn ứng dụng điện thoại nhiều; nhưng, than ôi, cũng đắt hơn nhiều.
Tất cả các tùy chọn này — đi đường ngẫu nhiên sinh ra trong đầu bạn, hướng dẫn trên điện thoại thông minh hoặc hướng dẫn của con người — hoạt động như các iterator trên tập hợp khổng lồ là các điểm tham quan và danh lam thắng cảnh ở Roma.
## 🏢 Cấu trúc

1. **Iterator** là interface khai báo các thao tác bắt buộc cho duyệt một tập hợp: lấy phần tử kế tiếp, trả về vị trí hiện tại, chạy lại vòng lặp,...
2. **Concrete Iterator** triển khai thuật toán cụ thể cho duyệt tập hợp. Đối tượng iterator nên theo dõi quá trình duyệt của nó. Điều này cho phép nhiều iterator duyệt cùng một tập hợp độc lập với nhau.
3. **Collection** là interface khai báo một hoặc nhiều phương thức để lấy các iterator tương thích với tập hợp. Lưu ý rằng kiểu trả về của phương thức phải được khai báo như interface iterator để cho concrete collection có thể trả về kiểu iterator khác.
4. **Concrete Collections** trả về phiên bản mới của một lớp concrete iterator riêng biệt mỗi khi client yêu cầu nó. Bạn có thể hỏi rằng, phần code còn lại của tập hợp ở đâu ? Không cần lo lắng, nó sẽ ở cùng một lớp. Chỉ là những chi tiết này không thực sự quan trọng đối với pattern, vì vậy ta sẽ bỏ qua chúng.
5. **Client** làm việc với cả tập hợp và iterator thông qua interface của chúng. Cách này giúp client không phải ghép với lớp cụ thể, cho phép bạn sử dụng các tập hợp và iterator khác trên cùng một code.
Thông thường, client không tạo iterator của nó, thay vào đó nó lấy chúng từ tập hợp. Tuy nhiên, trong một số trường hợp nhất định, client có thể tạo trực tiếp một cái; ví dụ, khi client xác định iterator đặc biệt của riêng nó.
## 👨💻 Mã giả
Trong ví dụ này, Iterator được dùng để duyệt qua một tập hợp đặc biệt, một đồ thị mạng xã hội tương tự như Facebook. Tập hợp cung cấp nhiều iterator để duyệt hồ sơ người dùng theo nhiều cách khác nhau.

Iterator "friend" có thể sử dụng để duyệt qua các bạn bè của hồ sơ người dùng được cho. Iterator "colleagues" cũng tương tự, ngoại trừ việc nó bỏ qua những người bạn không làm chung công ty với người dùng. Cả hai iterator triển khai cùng interface nên cho phép client lấy thông tin hồ sơ mà không cần đi sâu vào chi tiết triển khai như là xác thực hay gửi yêu cầu REST. .
Code client không phải ghép với lớp cụ thể vì nó làm việc với tập hợp và iterator thông qua interface. Nếu bạn định kết nối ứng dụng của bạn với mạng xã hội mới, bạn chỉ cần làm đơn giản là cung cấp cho nó tập hợp mới và lớp iterator mà không cần thay đổi code hiện có.
```c
// Interface collection phải khai báo phương thức factory cho
// tạo các iterator. Bạn có thể khai báo nhiều phương thức nếu
// nó có các kiểu lặp khác nhau trong chương trình của bạn.
interface SocialNetwork is
method createFriendsIterator(profileId):ProfileIterator
method createCoworkersIterator(profileId):ProfileIterator
// Mỗi concrete collection được ghép với tập hợp lớp concrete iterator
// mà nó trả về. Nhưng client không cần làm vậy, vì signature của phương
// thức này trả về interface iterator.
class Facebook implements SocialNetwork is
// ... Phần lớn code của tập hợp sẽ ở đây ...
// Code tạo iterator.
method createFriendsIterator(profileId) is
return new FacebookIterator(this, profileId, "friends")
method createCoworkersIterator(profileId) is
return new FacebookIterator(this, profileId, "coworkers")
// Interface chung cho tất cả iterator.
interface ProfileIterator is
method getNext():Profile
method hasMore():bool
// Lớp concrete iterator.
class FacebookIterator implements ProfileIterator is
// Iterator cần một tham chiếu đến tập hợp mà nó duyệt.
private field facebook: Facebook
private field profileId, type: string
// Đối tượng iterator duyệt tập hợp độc lập với các iterator
// khác. Do đó nó phải lưu trữ trạng thái iterator.
private field currentPosition
private field cache: array of Profile
constructor FacebookIterator(facebook, profileId, type) is
this.facebook = facebook
this.profileId = profileId
this.type = type
private method lazyInit() is
if (cache == null)
cache = facebook.socialGraphRequest(profileId, type)
// Mỗi lớp concrete iterator có triển khai riêng với interface
// iterator chung.
method getNext() is
if (hasMore())
currentPosition++
return cache[currentPosition]
method hasMore() is
lazyInit()
return currentPosition < cache.length
// Đây là một mẹo hữu ích khác: bạn có thể truyền một iterator
// đến lớp client thay vì cấp cho nó quyền truy cập toàn bộ tập
// hợp. Với cách này bạn sẽ không để lộ tập hợp với client
//
// Và một lợi ích khác: bạn có thể thay đổi cách client làm việc
// với tập hợp khi đang chạy bằng cách truyền vào nó iterator khác.
// Nó hoàn toàn khả thi vì code client không ghép vói lớp iterator
// cụ thể.
class SocialSpammer is
method send(iterator: ProfileIterator, message: string) is
while (iterator.hasMore())
profile = iterator.getNext()
System.sendEmail(profile.getEmail(), message)
// Lớp ứng dụng cấu hình tập hợp và iterator, và truyền chúng
// vào code client.
class Application is
field network: SocialNetwork
field spammer: SocialSpammer
method config() is
if working with Facebook
this.network = new Facebook()
if working with LinkedIn
this.network = new LinkedIn()
this.spammer = new SocialSpammer()
method sendSpamToFriends(profile) is
iterator = network.createFriendsIterator(profile.getId())
spammer.send(iterator, "Very important message")
method sendSpamToCoworkers(profile) is
iterator = network.createCoworkersIterator(profile.getId())
spammer.send(iterator, "Very important message")
```
## 💡 Ứng dụng
**🐞 Sử dụng Iterator khi tập hợp của bạn có cấu trúc dữ liệu phức tạp và bạn muốn ẩn sự phức tập đó khỏi client(vì lý do thuận tiện hay bảo mật).**
⚡ Iterator đóng gói các chi tiết công việc với cấu trúc dữ liệu phức tạp, và cung cấp nó cho client bằng những phương thức truy cập đơn giản đến các phần tử. Nó không những đem lại sự thuận lợi cho client, mà còn bảo về tập hợp khỏi các nguy cơ tấn công mà client có thể thực hiện nếu kết nối trực tiếp.
**🐞 Sử dụng Iterator khi muốn giảm code duyệt trùng lặp trên ứng dụng của bạn**
⚡ Code của các thuật toán lặp đặc biệt thường có xu hướng rất cồng kềnh. Khi được đặt trong logic nghiệp vụ của một ứng dụng, nó có thể làm mờ trách nhiệm của code gốc và làm cho nó khó bảo trì hơn. Chuyển code duyệt đến các iterator cụ thể có thể giúp bạn làm cho code của ứng dụng gọn gàng và sạch sẽ hơn.
**🐞 Sử dụng Iterator khi bạn muốn code của bạn có thể duyệt các cấu trúc dữ liệu khác nhau mà kiểu của cấu trúc đấy là không biết trước**.
⚡ Pattern cung cấp một vài interface chung cho cả tập hợp và iterator. Giả sử code của bạn hiện sử dụng các interface này, code sẽ vẫn hoạt động nếu bạn chuyển cho code các loại tập hợp và iterator khác nhau triển khai các interface này.
## 📋 Triển khai
1. Khai báo interface iterator. Ít nhất, nó phải có một phương thức để duyệt phần tử tiếp theo từ một tập hợp. Nhưng để thuận tiện, bạn có thể thêm một số phương pháp khác, chẳng hạn như duyệt phần tử trước đó, theo dõi vị trí hiện tại và kiểm tra kết thúc của lần lặp.
2. Khai báo interface collection và mô tả một phương pháp để nạp các iterator. Kiểu trả về phải trùng với kiểu của interface interator. Bạn có thể khai báo các phương thức tương tự nếu bạn định có một số nhóm iterator khác nhau.
3. Triển khai các lớp concrete iterator cho các tập hợp mà bạn muốn có thể duyệt được bằng iterator. Một đối tượng iterator phải được liên kết với một tập hợp đơn nhất. Thông thường, liên kết này được thiết lập thông qua phương thức khởi tạo của iterator.
4. Triển khai interface collection trong các lớp tập hợp của bạn. Ý tưởng chính là cung cấp cho client một lối tắt để tạo các iterator, được điều chỉnh cho một lớp concrete collection. Đối tượng tập hợp phải chuyển chính nó đến phương thức khởi tạo của iterator để thiết lập liên kết giữa chúng.
5. Xem qua code client để thay thế tất cả code duyệt tập hợp bằng việc sử dụng iterator. Client tìm nạp một đối tượng iterator mới mỗi khi nó cần lặp qua các phần tử của tập hợp.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Single Responsibility Principle*. Bạn có thể làm sạch code client và các tập hợp bằng cách trích xuất các thuật toán duyệt cồng kềnh thành các lớp riêng biệt.
✔️ *Open/Closed Principle*. Bạn có thể triển khai các kiểu tập hợp và iterator mới, và truyền nó vào code hiện có mà không gây ra ảnh hưởng gì.
✔️ Bạn có thể lặp song song trên cùng một tập hợp vì mỗi đối tượng iterator chứa trạng thái lặp riêng của nó.
✔️ Vì lý do tương tự, bạn có thể trì hoãn một lần lặp lại và tiếp tục nó khi cần.
### Nhược điểm
❌ Áp dụng pattern có thể là một việc làm quá mức cần thiết nếu ứng dụng của bạn chỉ hoạt động với các tập hợp đơn giản.
❌ Sử dụng iterator thể kém hiệu quả hơn so với việc duyệt trực tiếp các phần tử của một số tập hợp chuyên biệt.
## 🔁 Quan hệ với các pattern khác
Bạn có thể sử dụng **Iterator** để duyệt qua các cây **Composite**.
Bạn có thể sử dụng **Factory Method** cùng với **Iterator** để cho phép các lớp con của collection trả về các kiểu vòng lặp khác nhau tương thích với các collection.
Bạn có thể sử dụng **Memento** cùng với **Iterator** để nắm bắt trạng thái lặp lại hiện tại và khôi phục nó nếu cần.
Bạn có thể sử dụng **Visitor** cùng với **Iterator** để xem qua một cấu trúc dữ liệu phức tạp và thực hiện một số thao tác trên các phần tử của nó, ngay cả khi tất cả chúng đều có các lớp khác nhau
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/iterator)
================================================
FILE: behavioral-pattern/mediator/README.md
================================================
# Mediator
## 📜 Mục đích
Mediator là một desgin pattern thuộc nhóm behavioral giúp bạn giảm các phụ thuộc hỗn tạp giữa các đối tượng. Pattern hạn chế các giao tiếp trực tiếp giữa các đối tượng và buộc nó giao tiếp thông qua đối tượng mediator.

## 😟 Vấn đề
Giả sử bạn có một dialog cho tạo và chỉnh sửa thông tin khách hàng. Nó bao gồm các phần tử form khác nhau như text input, checkbox, button, ...

Một số phần tử trong form có thể tương tác với nhau. Ví dụ, khi chọn "I have a dog" ở một chechbox có thể sẽ dẫn đến hiện một input ẩn cho nhập tên chú chó đó. Hay khi submit một button sẽ phải xác thực các giá trị hợp lệ ở tất cả trường trước khi lưu dữ liệu.

*Các phần tử có quan hệ với nhau, nên thay đổi một phần tử có thể ảnh hưởng đến những cái khác*
Bằng cách triển khai trực tiếp logic bên trong code của phần tử form bạn sẽ làm cho lớp phần tử khó tái sử dụng ở các form khác trong ứng dụng. Ví dụ bạn không thể dùng lớp checkbox này cho các form khác vì nó đã được kết nối với input "tên chó". Hoặc là bạn có thể sử dụng tất cả các lớp liên quan đến hiển thị form người dùng hoặc là không dùng được gì cả.
## 😊 Giải pháp
Mediator đề nghị giải pháp là bạn nên dừng việc kết nối trực tiếp giữa các thành phần mà bạn muốn nó trở nên độc lập. Thay vào đó, các thành phần này sẽ phải cộng tác gián tiếp qua việc gọi một đối tượng mediator đặc biệt, đối tượng này mới là thứ gọi trực tiếp đến các thành phần thích hợp. Kết quả là các thành phần chỉ phụ thuộc vào lớp mediator duy nhất thay vì được ghép nối với hàng chục thành phần khác.
Trong ví dụ với form hồ sơ người dùng, lớp diago sẽ hành động như một mediator. Rất có thể, lớp dialog đã nhận thức được các phần tử con của nó, thế nên bạn không cần thêm phụ thuộc mới vào lớp.

Đây là một thay đổi có ý nghĩa to lớn với các phần tử trong form. Như với button submit. Trước đây mỗi lần người dùng click vào button, nó phải xác thực giá trị hợp lệ của tất cả phần tử riêng biệt trong form. Giờ đây nó chỉ có một công việc là thông báo cho dialog về thao tác click. Khi nhận được thông báo, dialog thực hiện xác thực bản thân nó hoặc truyền công việc cho các phần tử riêng biệt. Do đó thay vì bị ràng buộc với hàng tá phần tử trong form, button chỉ phụ thuộc vào dialog.
Bạn có thể làm nhiều hơn là nới lỏng các ràng buộc bằng việc trích xuất interface chung cho tất cả kiểu dialog. Interface sẽ khai báo phương thức thông báo cho tất cả phần tử của form để thông báo đến dialog mỗi khi có sự kiện gì diễn ra với bọn chúng. Do đó, button submit của ta bây giờ có thể làm việc với bất kỳ dialog nào triển khai interface này.
Bằng cách này, Mediator giúp bạn gói một trang web phức tạp với các đối tượng có quan hệ khác nhau vào trong một đối tượng mediator đơn giản. Ít ràng buộc và phụ thuộc hơn, giúp nó dễ thay đổi, mở rộng và tái sử dụng hơn.
## 🚗 Thế Giới Thực

Các phi công của máy bay đến hoặc rời đi khỏi khu vực kiểm soát của sân bay không phải liên lạc trực tiếp với nhau. Thay vào đó, họ trao đổi với một nhân viên kiểm soát không lưu, người ngồi trong một tòa tháp cao ở đâu đó gần đường băng. Nếu không có kiểm soát viên không lưu, các phi công sẽ cần phải biết về mọi máy bay trong khu vực lân cận sân bay, thảo luận về các ưu tiên hạ cánh với một nhóm gồm hàng chục phi công khác. Điều đó có thể sẽ làm tăng vọt số liệu thống kê về các vụ tai nạn máy bay.
Tháp không cần điều khiển toàn bộ chuyến bay. Nó chỉ tồn tại để thực thi các ràng buộc trong khu vực hạ cánh vì số lượng các máy bay ở đó có thể quá tải đối với một phi công.
## 🏢 Cấu trúc

1. **Component** là các lớp khác nhau bao gồm các logic nghiệp vụ. Mỗi component có một tham chiếu đến một mediator, khai báo kiểu của interface mediator. Component không cần biết về lớp thực sự của mediator, nên bạn có thể sử dụng lại component cho các chương trình khác bằng cách liên kết nó với một mediator khác.
2. **Mediator** là interface khai báo phương thức giao tiếp giữa các component, nó thường khai báo một phương thức thông báo duy nhất. Component có thể truyền bất kỳ ngữ cảnh nào như các tham số của phương thức này bao gồm cả đối tượng của chúng, nhưng chỉ trong trường hợp không diễn ra kết ghép giữa component nhận và lớp của người gửi.
3. **Concrete Mediator** đóng gói quan hệ giữa các component khác nhau. Concrete mediator thường giữ tham chiếu để tất cả component nó quản lý và thỉnh thoảng quản lý cả vòng đời của chúng.
4. Component không phải biết về các component khác. Nếu một điều gì quan trọng diễn ra với một component, nó chỉ việc thông báo đến mediator. Khi mediator nhận thông báo nó có thể xác định được người gửi dễ dàng, chỉ như vậy là đủ để nó quyết định component nào sẽ được kích hoạt khi trả về.
Từ góc nhìn của một component, tất cả trông giống như một hộp đen. Người gửi không biết ai sẽ xử lý yêu cầu của mình và người nhận không biết ai đã gửi yêu cầu ngay từ đầu.
## 👨💻 Mã giả
Trong ví dụ này, Mediator giúp bạn loại bỏ sự phụ thuộc lẫn nhau giữa các lớp UI khác nhau: button, checkbox và text labels.

Một phần tử được kích hoạt bởi người dùng, không cần giao tiếp trực tiếp với các phần tử khác. Thay vào đó, các phần tử chỉ cần cho mediator của chúng biết khi có sự kiện diễn ra, truyền thông tin ngữ cảnh cùng với thông báo.
Trong ví dụ này, các dialog hành động như một mediator. Nó biết làm thế nào để các phần tử cụ thể cộng tác với nhau và tạo điều kiện cho chúng kết nối gián tiếp với nhau. Mỗi khi nhận thông báo về một sự kiện, dialog quyết định phần tử nào sẽ giải quyết và chuyền hướng lệnh gọi phù hợp.
```c
// Interface mediator khai báo một phương thức được dùng bởi
// các component để thông báo cho mediator về các sự kiện khác
// nhau. Mediator sẽ phản ứng với sự kiện và truyền thực thi
// cho các component khác.
interface Mediator is
method notify(sender: Component, event: string)
// Lớp concrete mediator. Các kết nối phức tạp giữa các
// component riêng biệt đã được gỡ rối và chuyền vào mediator.
class AuthenticationDialog implements Mediator is
private field title: string
private field loginOrRegisterChkBx: Checkbox
private field loginUsername, loginPassword: Textbox
private field registrationUsername, registrationPassword,
registrationEmail: Textbox
private field okBtn, cancelBtn: Button
constructor AuthenticationDialog() is
// Tạo tất cả đối tượng component và truyền mediator
// hiện tại vào hàm khởi tạo để thiết lập liên kết.
// Khi điều gì đó diễn ra với một component, nó thông báo cho
// mediator. Khi nhận được thông báo, mediator sẽ làm gì đó
// hoặc truyền yêu cầu đến component khác.
method notify(sender, event) is
if (sender == loginOrRegisterChkBx and event == "check")
if (loginOrRegisterChkBx.checked)
title = "Log in"
// 1. Hiện form đăng nhập
// 2. Ẩn form đăng ký.
else
title = "Register"
// 1. Hiện form đăng ký
// 2. Ẩn form đăng nhập.
if (sender == okBtn && event == "click")
if (loginOrRegister.checked)
// Tìm kiếm người dùng bằng chứng chỉ đăng nhập.
if (!found)
// Hiện thông báo lỗi trên trường đăng nhập.
else
// 1. Tạo tài khoản người dùng sử dụng dữ liệu
// từ trường đăng ký.
// 2. Đăng nhập người dùng.
// ...
// Component giao tiếp với mediator thông qua interface mediator.
// Nhờ điều đó, bạn có thể dùng cùng một component trong các
// bối cảnh khác nhau bằng liên kết với các đối tượng mediator
// khác nhau.
class Component is
field dialog: Mediator
constructor Component(dialog) is
this.dialog = dialog
method click() is
dialog.notify(this, "click")
method keypress() is
dialog.notify(this, "keypress")
// Mỗi concrete component không giao tiếp với nhau. Chúng chỉ
// có một kênh giao tiếp để gửi thông báo đến mediator.
class Button extends Component is
// ...
class Textbox extends Component is
// ...
class Checkbox extends Component is
method check() is
dialog.notify(this, "check")
// ...
```
## 💡 Ứng dụng
**🐞 Sử dụng Mediator khi việc thay đổi một vài lớp trở nên khó khăn do chúng được kết ghép chặt chẽ với các lớp khác**
⚡ Pattern giúp bạn trích xuất các quan hệ giữa các lớp vào một lớp riêng biệt, cô lập bất kỳ thay đổi nào đến một thành phần cụ thể khỏi các thành phần còn lại.
**🐞 Sử dụng Mediator khi bạn không thể dùng lại một thành phần ở chương trình khác vì nó phụ thuộc vào các thành phần khác**.
⚡ Sau khi áp dụng Mediator, các thành phần cụ thể sẽ không biết đến các thành phần khác. Chúng chỉ giao tiếp với nhau một cách gián tiếp thông qua đối tượng mediator. Để dùng lại một thành phần ở ứng dụng khác, bạn cần cung cấp cho nó một lớp mediator mới.
**🐞 Sử dụng Mediator khi bạn phải tạo hàng tấn thành phần con chỉ để sử dụng lại vài hành vi cơ bản cho các bối cảnh khác nhau**.
⚡ Vì tất cả các mối quan hệ giữa các thành phần được chứa trong mediator, nên thật dễ dàng xác định các cách hoàn toàn mới cho các thành phần này cộng tác bằng cách thêm các lớp mediator mới mà không cần phải thay đổi chính các thành phần đó.
## 📋 Triển khai
1. Xác định xem một nhóm các lớp kết nối chặt chẽ có tốt hơn việc chúng độc lập với nhau không(có dễ bảo trì hay dùng lại các lớp này không).
2. Khai báo interface mediator và mô tả giao thức giao tiếp mong muốn giữa mediator và các thành phần khác. Trong hầu hết trường hợp, một phương thức duy nhất cho nhận các thông báo từ các thành phần là đủ.
Interface này là cốt yếu khi bạn muốn sử dụng lại lớp thành phần ở ngữ cảnh khác. Miễn là thành phần làm việc với mediator thông qua interface chung, bạn có thể liên kết thành phần với triển khai khác của mediator.
3. Triển khai lớp mediator cụ thể. Lớp này dùng để lưu trữ tham chiếu đến tất cả thành phần mà nó quản lý.
4. Bạn có thể để mediator chịu trách nhiệm tạo và huỷ các đối tượng thành phần. Lúc này, mediator sẽ giống như một factory hay facade.
5. Các thành phần nên lưu một tham chiếu đến đối tượng mediator. Kết nối này thường được thiết lập ở hàm khởi tạo thành phần, nơi một đối tượng mediator được truyền như một tham số.
6. Thay đổi code của component này sẽ gọi đến phương thức thông báo của mediator thay vì đến phương thức của các thành phần khác. Trích xuất code để gọi đến thành phần khác vào lớp mediator. Thực thi code này bất cứ khi nào mediator nhận được thông báo.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Single Responsibility Principle*. Bạn có thể trích xuất giao tiếp giữa các thành phần khác vào một nơi duy nhất, giúp nó dễ hiểu và bảo trì hơn.
✔️ *Open/Closed Principle*. Bạn có thể thêm mediator mới mà không ảnh hưởng gì đến các thành phần thực sự.
✔️ Bạn có thể làm giảm liên kết giữa các thành phần khác nhau trong chương trình.
✔️ Bạn có thể sử dụng lại các thành phần cụ thể một cách dễ dàng.
### Nhược điểm
❌ Theo thời gian mediator có thể phát triển thành một [Đối tượng thượng đế](https://vi.wikipedia.org/wiki/Đối_tượng_thượng_đế_(Lập_trình_máy_tính))
## 🔁 Quan hệ với các pattern khác
**Chain of Responsibility**, **Command**, **Mediator** và **Observer** giải quyết các cách khác nhau để kết nối người gửi và người nhận yêu cầu:
- **CoR** chuyển một yêu cầu tuần tự dọc theo một chuỗi động gồm những người nhận tiềm năng cho đến khi một trong số họ xử lý nó.
- **Command** thiết lập các kết nối một chiều giữa người gửi và người nhận.
- **Mediator** loại bỏ các kết nối trực tiếp giữa người gửi và người nhận, buộc họ phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- **Observer** cho phép người nhận đăng ký động và hủy đăng ký nhận yêu cầu.
**Facade** và **Mediator** có những công việc tương tự nhau: cố gắng tổ chức sự hợp tác giữa nhiều lớp được kết hợp chặt chẽ với nhau.
- **Facade** xác định một interface đơn giản cho một hệ thống con của các đối tượng, nhưng nó không giới thiệu bất kỳ chức năng mới nào. Bản thân hệ thống con không biết về facade. Các đối tượng trong hệ thống con có thể giao tiếp trực tiếp.
- **Mediator** tập trung giao tiếp giữa các thành phần của hệ thống. Các thành phần chỉ biết về đối tượng mediator và không giao tiếp trực tiếp.
Sự khác biệt giữa **Mediator** và **Observer** thường khó nắm bắt. Trong hầu hết các trường hợp, bạn có thể triển khai một trong các mẫu này; nhưng đôi khi bạn có thể áp dụng đồng thời cả hai. Hãy xem chúng ta có thể làm điều đó như thế nào.
- Mục tiêu chính của **Mediator** là loại bỏ sự phụ thuộc lẫn nhau giữa một tập hợp các thành phần hệ thống. Thay vào đó, các thành phần này trở nên phụ thuộc vào một đối tượng mediator duy nhất. Mục tiêu của **Observer** là thiết lập các kết nối động một chiều giữa các đối tượng, nơi một số đối tượng đóng vai trò là cấp dưới của những đối tượng khác.
- Có một cách triển khai phổ biến của **Mediator** vào **Observer**. Đối tượng mediator đóng vai trò là publisher và các thành phần đóng vai trò là subscribers, đăng ký và hủy đăng ký tham gia các sự kiện của mediator. Khi **Mediator** được triển khai theo cách này, nó có thể trông rất giống với **Observer**.
- Nếu thấy bối rối, hãy nhớ rằng bạn có thể triển khai **Mediator** theo những cách khác. Ví dụ: bạn có thể liên kết vĩnh viễn tất cả các thành phần với cùng một đối tượng mediator. Việc triển khai này sẽ không giống với **Observer** nhưng vẫn sẽ là một bản sao của **Mediator**.
- Bây giờ hãy tưởng tượng một chương trình mà tất cả các thành phần đã trở thành publisher, cho phép các kết nối động với nhau. Sẽ không có đối tượng mediator tập trung, chỉ có một nhóm observer phân tán.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/mediator)
================================================
FILE: behavioral-pattern/memento/README.md
================================================
# Memento
## 📜 Mục đích
Memento là một desgin pattern thuộc nhóm behavioral giúp bạn lưu và phục hồi trạng thái trước đó của một đối tượng mà không để lộ chi tiết triển khai của nó

## 😟 Vấn đề
Tưởng tượng bạn đang tạo một ứng dụng soạn thảo văn bản. Bên cạnh việc chỉnh sửa đơn giản, bạn còn phải tạo chức năng định dạng văn bản, thêm ảnh, chỉnh phông,...
Vào một lúc nào đó, bạn quyết định thêm chức năng giúp người dùng hoàn tác bất kỳ thao tác nào được thực hiện trên văn bản. Chức năng này rất phổ biến trong thời gian gần đây và người dùng sẽ mong muốn là mọi ứng dụng đều có nó.
Để triển khai, bạn chọn cách tiếp cận trực tiếp. Là trước khi thực hiện bất kỳ thao tác nào, ứng dụng sẽ ghi lại trạng thái của tất cả đối tượng trong nó và lưu chúng vào một vài nơi lưu trữ. Sau đó, khi người dùng muốn hoàn tác hành động, ứng dụng sẽ lấy snapshot (bản lưu nhanh) gần nhất trong lịch sử và dùng nó để phục hồi trạng thái của mọi đối tượng.

Bây giờ ta xem xét kỹ snapshot của các trạng thái này. Câu hỏi đặt ra là làm thế nào để bạn tạo chính xác chúng? Có lẽ bạn sẽ đi qua tất cả trường trong đối tượng và sao chép giá trị của chúng rồi lưu vào bộ nhớ. Tuy nhiên nó sẽ chỉ hoạt động nếu đối tượng của bạn không hạn chế truy cập đến nội dung của nó. Không may, phần lớn đối tượng thực sẽ không để những thứ bên ngoài truy cập vào bên trong của nó dễ dàng, nó sẽ ẩn tất cả dữ liệu có ích vào các trường riêng tư.
Tạm thời ta bỏ qua vấn đề này và mặc định rằng tất cả đối tượng của chúng ta đều như những con hà mã: thích các quan hệ mở và công khai trạng thái của chúng. Lúc này, ngay cả khi cách tiếp cận trên giải quyết được vấn đề và giúp bạn tạo snapshot của trạng thái đối tượng tuỳ ý, thì nó vẫn tồn đọng nhiều vấn đề nghiêm trọng khác. Trong tương lai, khi bạn quyết định tái cấu trúc một vài lớp chỉnh sửa, tức là thêm hoặc xoá một vài trường. Điều này sẽ không dễ dàng vì bạn phải thay đổi tất cả các lớp chịu trách nhiệm cho sao chép trạng thái của đối tượng bị ảnh hưởng.

Hơn thế nữa. Hãy xem xét các snapshot trạng thái của trình soạn thảo. Dữ liệu trong nó bao gồm những gì? Ở mức tối thiểu, nó phải bao gồm các văn bản thực, toạ độ con trỏ, vị trí hiện tại đang scroll,... Để tạo snapshot, bạn cần phải tìm kiếm các giá trị này và đặt chúng vào trong một dạng container.
Có thể, bạn sẽ lưu một lượng đối tượng container này trong một vài danh sách để biểu diễn lịch sử thao tác. Do đó, container có lẽ là sẽ trở thành đối tượng của một lớp. Lớp này không có phương thức, những có nhiều trường để ánh xạ trạng thái của trình soạn thảo. Để cho phép các đối tượng khác viết và đọc dữ liệu từ snapshot, bạn phải công khai tất cả các trường của nó. Điều này vô tình làm lộ trạng thái của ứng dụng bất kể nó riêng tư hay không. Các lớp khác sẽ trở nên phụ thuộc vào mọi thay đổi dù rất nhỏ ở lớp snapshot, ngược lại nếu các trường và phương thức này riêng tư thì những gì diễn ra trong đây sẽ không ảnh hưởng gì đến bên ngoài lớp.
Có vẻ như chúng ta đã đi đến ngõ cụt: bạn để lộ tất cả các chi tiết bên trong của các lớp, khiến chúng quá mỏng manh(dễ bị thay đổi), còn nếu hạn chế quyền truy cập vào trạng thái của chúng, thì bạn không thể tạo snapshot. Có cách nào khác để thực hiện "hoàn tác" không?
## 😊 Giải pháp
Tất cả vấn đề trên mà ta gặp phải đều được gây ra bởi hành vi phá vỡ tính đóng gói. Một vài đối tượng cố làm nhiều hơn những gì chúng phải làm. Để thu thập dữ liệu cần thiết cho thực hiện một vài hành động, chúng xâm lấn sang các không gian riêng tư của các đối tượng khác thay vì để các đối tượng đó thực hiện hành động thực.
Memento đề xuất giải pháp uỷ thác việc tạo các snapshot trạng thái cho các chủ sở hữu thực của trạng thái đó, tức là đối tượng gốc. Do đó, thay vì để đối tượng khác cố sao chép trạng thái của trình soạn thảo từ bên ngoài, lớp trình soạn thảo sẽ tự tạo snapshot của chúng vì nó có đầy đủ quyền truy cập vào trạng thái của chúng.
Ý tưởng lưu trữ bản sao của trạng thái đối tượng vào một đối tượng đặc biệt gọi là memento. Nội dung của memento không thể bị truy cập bởi bất kỳ đối tượng nào khác ngoại trừ cái đã tạo ra nó. Các đối tượng khác phải giao tiếp với memento bằng một interface giới hạn, cho phép nạp metadata của snapshot(thời gian tạo, tên thao tác, ...) nhưng không được đụng đến trạng thái của đối tượng ban đầu có trong snapshot.

*Originator có đầy đủ quyền truy cập đến memento, trong khi caretaker chỉ có thể thể truy cập đến siêu dữ liệu.*
Một chính sách hạn chế như vậy giúp bạn lưu memento bên trong các đối tượng khác, thường được gọi là caretaker. Vì caretaker làm việc với memento thông qua interface giới hạn, nó không thể can thiệp vào trạng thái được lưu trong memento. Trong khi đó, originator có thể truy cập đến tất cả trường trong memento, cho phép nó khôi phục trạng thái trước đó theo ý muốn.
Trong ví dụ trình soạn thảo của chúng ta, ta có thể tạo một lớp lịch sử riêng biệt như một caretaker. Ngăn xếp các memento được lưu bên trong caretaker sẽ phát triển mỗi khi trình soạn thảo thực thi một thao tác. Bạn có thể render ngăn xếp vào UI của ứng dụng, như hiển thị lịch sử các thao tác trước đó của người dùng.
Khi người dùng thực hiện hoàn tác, lịch sử sẽ lấy memento gần nhất khỏi ngăn xếp và truyền nó trở lại vào trình soạn thảo, yêu cầu phục hồi. Vì trình soạn thảo có đầy đủ truy cập đến memento, nó sẽ thay đổi trạng thái của nó với giá trị nhận được từ memento.
## 🏢 Cấu trúc
### Triển khai dạng lớp lồng nhau
Cách triển khai cổ điển dựa trên các lớp lồng nhau, khả dụng với các ngôn ngữ lập trình phổ biến như C++, C#, Java.

1. **Originator** lớp tạo các snapshot cho trạng thái của nó, cũng như phục hồi trạng thái của nó từ snapshot khi cần.
2. **Memento** là đối tượng giá trị hành động như một snapshot của trạng thái của originator. Thường thì memento sẽ bất biến và truyền dữ liệu cho nó chỉ một lần thông qua hàm khởi tạo.
3. **Caretaker** không chỉ biết "khi nào" và "tại sao" phải lưu trạng thái của originator, mà còn biết trạng thái sẽ được phục hồi khi nào.
Một caretaker có thể theo dõi lịch sử của originator bằng cách lưu trữ một ngăn xếp memento. Khi originator đi ngược về lịch sử, caretaker tìm nạp memento trên cùng từ ngăn xếp và truyền nó vào phương thức phục hồi của originator.
4. Trong triển khai này, lớp memento được lồng trong originator. Cách này giúp originator truy cập đến tất cả trường và phương thức của memento, kể cả khi chúng là riêng tư. Mặt khác, caretaker bị giới hạn truy cập đến trường và phương thức của memento, nó chỉ lưu trữ memento trong một ngăn xếp chứ không thể can thiếp vào trạng thái của chúng.
### Triển khai dựa trên interface trung gian
Có một cách triển khai thay thế, phù hợp với các ngôn ngữ lập trình không hỗ trợ các lớp lồng nhau (vâng, tôi đang nói về PHP).

1. Nếu không dùng lớp lồng nhau, bạn có thể hạn chế truy cập đến trường của memento bằng cách thiết lập một quy ước rằng caretaker có thể làm việc với memento chỉ qua một interface trung gian khai báo rõ ràng, nó chỉ khai báo phương thức cho liên kết đến siêu dữ liệu của memento.
2. Mặt khác, originator có thể làm việc với một đối tượng memento trực tiếp, truy cập trường và phương thức được khai báo trong lớp memento. Nhược điểm của các tiếp cận này là bạn cần khai báo tất cả thành phần của memento công khai.
### Triển khai với tính đóng gói chặt chẽ hơn
Có một cách triển khai khác rất hữu ích khi bạn không muốn để lại mọt rủi ro nhỏ nhất nào cho các lớp khác truy cập vào trạng thái của trình khởi tạo thông qua memento.

1. Triển khai này cho phép nhiều kiểu của originator và memento. Mỗi originator làm việc với lớp memento phù hợp. Không có originator cũng như memento nào để lộ trạng thái của nó với bên ngoài.
2. Caretaker bây giờ bị giới hạn rõ ràng trong việc thay đổi trạng thái được lưu trong memento. Hơn thế nữa, lớp caretaker sẽ độc lập với originator vì phương thức phục hồi giờ được định nghĩa trong lớp memento.
3. Mỗi memento trở thành một liên kết với originator đã tạo nó. Originator truyền vào nó hàm khởi tạo của memento, cùng với giá trị trạng thái của nó. Vì quan hệ chặt chẽ giữa các lớp, nên một memento có thể phục hồi trạng thái của originator, với điều kiện là phần sau đã xác định các bộ thiết lập thích hợp.
## 👨💻 Mã giả
Ví dụ này sử dụng Memento cùng với Commend để lưu trữ snapshot về trạng thái của trình soạn thảo văn bản phức tạp và khôi phục trạng thái trước đó từ các snapshot này khi cần.

Đối tượng command hành động như một caretaker. Chúng tìm nạp memento của trình soạn thảo trước khi thực thi thao tác liên quan đến command. Khi người dùng thực hiện hoàn tác câu lệnh gần nhất, trình soạn thảo có thể sử dụng memento được lưu trong command để hoàn tác trạng thái trước đó của nó.
Lớp memento không khai báo bất kỳ trường công khai nào dù là getter hay setter. Do đó không có đối tượng nào có thể thay đổi nội dung của nó. Memento được liên kết với đối tượng soạn thảo đã tạo nó. Điều này giúp một memento phục hồi trạng thái của trình soạn thảo được liên kết bằng cách truyền dữ liệu thông qua setter trên đối tượng soạn thảo. Vì memento được liên kết với đối tượng soạn thảo cụ thể, bạn có thể làm cho ứng dụng hỗ trợ nhiều trình soạn thảo độc lập với ngăn xếp hoàn tác trung tâm.
```c
// Originator tổ chức một vài dữ liệu quan trọng có thể thay đổi
// nhiều lần. Nó còn định nghĩa một phương thức cho lưu trữ và
// phục hồi trạng thái của nó.
class Editor is
private field text, curX, curY, selectionWidth
method setText(text) is
this.text = text
method setCursor(x, y) is
this.curX = x
this.curY = y
method setSelectionWidth(width) is
this.selectionWidth = width
// Lưu trạng thái hiện tại vào trong memento.
method createSnapshot():Snapshot is
// Memento là một đối tượng bất biến; điều này
// giải thích tại sao originator truyền trạng
// thái của nó như tham số vào hàm khởi tạo
// của memento.
return new Snapshot(this, text, curX, curY, selectionWidth)
// Lớp memento lưu trữ trạng thái trước đó của trình soạn thảo.
class Snapshot is
private field editor: Editor
private field text, curX, curY, selectionWidth
constructor Snapshot(editor, text, curX, curY, selectionWidth) is
this.editor = editor
this.text = text
this.curX = x
this.curY = y
this.selectionWidth = selectionWidth
// Cùng thời điểm, trạng thái trước đó của trình soạn thảo
// có thể phục hồi bằng cách sử dụng đối tượng memento.
method restore() is
editor.setText(text)
editor.setCursor(curX, curY)
editor.setSelectionWidth(selectionWidth)
// Đối tượng command hành động như một caretaker. Trong trường
// hợp này, command lấy memento trước khi trạng thái của originator
// thay đổi. Khi hoàn tác, nó phục hồi trạng thái của originator
// từ memento.
class Command is
private field backup: Snapshot
method makeBackup() is
backup = editor.createSnapshot()
method undo() is
if (backup != null)
backup.restore()
// ...
```
## 💡 Ứng dụng
**🐞 Sử dụng Memento khi bạn muốn tạo snapshot của trạng thái đối tương để phục hồi trạng trước đó của đối tượng**
⚡ Memento giúp bạn tạo bản sao chép đầy đủ trạng thái của một đối tượng, kể cả trường riêng tư, và lưu chúng riêng biệt với đối tượng. Trong khi phần lớn mọi người sử dụng pattern này cho hoàn tác thì nó cũng được dùng cho xử lý giao dịch(nếu bạn cần khôi phục thao tác lỗi).
**🐞 Sử dụng Memento khi truy cập trực tiếp tới trường/getter/setter của đối tượng vi phạm tính đóng gói**
⚡ Memento giúp đối tượng tự chịu trách nhiệm tạo snapshot trạng thái của nó. Không đối tượng nào khác có thể đọc snapshot, giúp dữ liệu trạng thái của đối tượng ban đầu trở nên an toàn và bảo mật.
## 📋 Triển khai
1. Xác định lớp nào đóng vai trò originator. Điều này là cần thiết để biết chương trình sử dụng một đối tượng trung tâm hay nhiều đối tượng nhỏ hơn.
2. Tạo lớp memento. Từng cái một, khai báo tập hợp trường ánh xạ các trường được khai báo ở lớp originator.
3. Làm memento bất biến. Memento chỉ nhận dữ liệu một lần thông qua hàm khởi tạo. Lớp này không có setter.
4. Nếu ngôn ngữ lập trình hỗ trợ lồng lớp, lồng memento vào originator. Nếu không, trích xuất interface trống từ lớp memento và làm tất cả đối tượng khác sử dụng nó tham chiếu đến memento. Bạn có thể thêm thao tác metadata đến interface nhưng không để lộ thứ gì của trạng thái originator.
5. Thêm một phương thức cho tạo memento ở lớp originator. Originator chỉ truyền trạng thái của nó đến memento thông qua một hoặc nhiều tham số của hàm khởi tạo memento.
Kiểu trả về của phương thức nên là interface bạn trích xuất ở bước trước đó (giả sử bạn trích xuất nó ở mọi nơi). Bên trong nó, phương thức tạo memento nên làm việc trực tiếp với lớp memento.
6. Thêm một phương thức cho phục hồi trạng thái của lớp originator. Nó chấp nhận một đối tượng memento như một tham số. Nếu bạn trích xuất một interface ở bước trước, làm nó có kiểu của tham số. Trong trường hợp này, bạn cần ép kiểu đối tượng vào lớp memento, vì originator cần đầy đủ truy cập đến đối tượng này.
7. Caretaker, cho dù nó biểu diễn một đối tượng command, một lịch sử hoặc một cái gì đó hoàn toàn khác, thì cũng cần biết khi nào yêu cầu memento mới từ originator, cách lưu trữ chúng và khi nào thì khôi phục originator bằng một memento cụ thể.
8. Mối liên hệ giữa caretaker và originator có thể được chuyển vào lớp memento. Trong trường hợp này, mỗi memento phải được kết nối với originator đã tạo ra nó. Phương thức khôi phục cũng sẽ chuyển sang lớp memento. Tuy nhiên, tất cả điều này sẽ chỉ có ý nghĩa nếu lớp memento được lồng vào originator hoặc lớp originator cung cấp đủ setter để ghi đè trạng thái của nó.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn có thể tạo snapshot cho trạng thái đối tượng mà không vi phạm tính đóng gói.
✔️ Bạn có thể đơn giản hoá của của originator bằng cách cho phép caretaker duy trì lịch sử trạng thái của originator.
### Nhược điểm
❌ Ứng dụng có thể tốn nhiều RAM nếu client thường xuyên tạo memento.
❌ Caretaker nên theo dõi vòng đời của originator để có thể huỷ memento hết hạn.
❌ Nhiều ngôn ngữ lập trình động như PHP, Python và JavaScript không bảo đảm trạng thái trong memento sẽ an toàn.
## 🔁 Quan hệ với các pattern khác
Bạn có thể sử dụng **Memento** cùng với **Iterator** để nắm bắt trạng thái lặp lại hiện tại và khôi phục nó nếu cần.
Bạn có thể sử dụng **Command** và **Memento** cùng nhau khi thực hiện "hoàn tác". Trong trường hợp này, các command chịu trách nhiệm thực hiện các hoạt động khác nhau trên một đối tượng đích, trong khi các mementos lưu trạng thái của đối tượng đó ngay trước khi command được thực thi.
Đôi khi **Prototype** có thể là một giải pháp thay thế đơn giản hơn cho **Memento**. Điều này hoạt động nếu đối tượng, trạng thái mà bạn muốn lưu trữ trong lịch sử, khá đơn giản và không có liên kết đến tài nguyên bên ngoài hoặc các liên kết dễ thiết lập lại.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/memento)
================================================
FILE: behavioral-pattern/observer/README.md
================================================
# Observer
## 📜 Mục đích
Observer là một design pattern thuộc nhóm behavioral giúp bạn định nghĩa một cơ chế đăng ký để thông báo cho nhiều đối tượng về bất kỳ sự kiện nào diễn ra với đối tượng mà chúng đang quan sát.

## 😟 Vấn đề
Tưởng tượng bạn có hai kiểu đối tượng: `Customer` và `Store`.
Khách hàng thường sẽ bị hấp dẫn với một vài thương hiệu sản phẩm nổi bật, ví dụ như mẫu iPhone mới sẽ sớm được bán ở của hàng. Thế nên họ sẽ đến cửa hàng mỗi ngày để kiểm tra sản phẩm đã có bán chưa. Nhưng nếu sản phẩm vẫn chưa nhập về, thì phần lớn công sức của họ cho mỗi chuyến đi sẽ vô nghĩa.

Thế nên, cửa hàng sẽ gửi hàng tấn mail (có thể là spam) cho tất cả khách hàng mỗi lần có sản phẩm mới. Điều này giúp khách hàng tránh những chuyến đi vô nghĩa đến cửa hàng. Nhưng bù lại, nó sẽ làm cho các khách hàng khác (những người không có hứng thú với sản phẩm mới) khó chịu.
Có vẻ như chúng ta đã xảy ra xung đột. Hoặc khách hàng lãng phí thời gian kiểm tra sản phẩm đã bán chưa hoặc cửa hàng lãng phí nguồn lực để thông báo thừa cho khách hàng.
## 😊 Giải pháp
Đối tượng có trạng thái hấp dẫn thường được gọi là subject(chủ thể), nhưng vì nó cũng sẽ thông báo cho các đối tượng khác về những thay đổi đối với trạng thái của nó, nên ta sẽ gọi nó là **publisher**. Tất cả đối tượng khác muốn theo dõi trạng thái của publisher được gọi là **subscriber**.
Pattern Observer đề nghị giải pháp là bạn thêm một cơ chế đăng ký đến lớp publisher để các đối tượng riêng biệt có thể đăng ký hoặc huỷ đăng ký một dòng các sự kiện xảy đến từ publisher. Thực tế, cơ chế này bao gồm một trường mảng cho lưu trữ danh sách tham chiếu đến đối tượng subscriber và nhiều phương thức công khai cho phép thêm hay xoá subscriber khỏi danh sách.

Bây giờ, bất cứ khi nào có sự kiện quan trọng diễn ra với publisher, nó đi qua tất cả subscriber và gọi phương thức thông báo cụ thể trên đối tượng của chúng.
Ứng dụng thực có thể có hàng tá lớp subscriber khác nhau quan tâm đến việc theo dõi các sự kiện của cùng một lớp publisher. Bạn sẽ không muốn ghép publiser với tất cả các lớp đó. Bên cạnh đó, bạn thậm chí có thể không biết về một số trong số chúng trước nếu lớp publisher của bạn được người khác sử dụng.
Đó là lý do tại sao cho việc tất cả subscriber phải triển khai cùng một interface và publisher chỉ giao tiếp với chúng qua interface đó. Interface này phải khai báo phương thức thông báo cùng với một tập hợp các tham số mà publisher có thể sử dụng để chuyển một số dữ liệu ngữ cảnh cùng với thông báo.

Nếu ứng dụng của bạn có nhiều kiểu publisher khác nhau và bạn muốn làm cho subscriber của mình tương thích với tất cả chúng, bạn có thể tiến xa hơn nữa và khiến tất cả các publisher tuân theo cùng một interface. Interface này sẽ chỉ cần mô tả một số phương pháp đăng ký. Interface sẽ cho phép subscriber quan sát trạng thái của publisher mà không cần kết nối đến các lớp cụ thể của chúng.
## 🚗 Thế Giới Thực

Nếu bạn đăng ký một tờ báo hoặc tạp chí, bạn không cần phải đến cửa hàng để kiểm tra xem số tiếp theo có sẵn hay không. Thay vào đó, nhà xuất bản gửi các số báo mới trực tiếp đến hộp thư của bạn ngay sau khi xuất bản hoặc thậm chí trước.
Nhà xuất bản duy trì danh sách người đăng ký và biết họ quan tâm đến tạp chí nào. Người đăng ký có thể rời khỏi danh sách bất kỳ lúc nào khi họ muốn ngăn nhà xuất bản gửi các số tạp chí mới cho họ.
## 🏢 Cấu trúc

1. **Publisher** phát hành các sự kiện mà các đối tượng khác quan tâm. Các sự kiện này diễn ra khi publisher thay đổi trạng thái của nó hoặc thực thi một vài hành vi. Publisher bao gồm một kết cấu đăng ký cho phép subscriber mới tham gia hay subscriber hiện tại rời khỏi danh sách.
2. Khi một sự kiện mới diễn ra, publisher sẽ đi qua danh sách đăng ký và gọi phương thức thông báo được khai báo ở interface subscriber cho từng đối tượng subscriber.
3. **Subscriber** là interface khai báo interface thông báo. Trong hầu hết trường hợp, nó bao gồm một phương thức cập nhật duy nhất. Phương thức này có nhiều tham số giúp publisher truyền một vài chi tiết sự kiện cùng với cập nhật.
4. **Concrete Subscriber** thực hiện một vài hành động phản hồi lại thông báo được phát hành bởi publisher. Tất cả các lớp này phải triển khai cùng interface thế nên publisher không cần ghép với lớp cụ thể.
5. Thông thường, subscriber cần một vài thông tin ngữ cảnh để xử lý cập nhật chính xác. Vì lý do này, publisher truyền một vài dữ liệu ngữ cảnh như các tham số cho phương thức thông báo. Publisher có thể truyền chính bản thân nó như một tham số, để subscriber có thể nạp bất kỳ dữ liệu cần thiết nào trực tiếp.
6. **Client** tạo đối tượng publisher và subscriber riêng biệt, sau đó subscriber đăng ký các bản cập nhật publisher.
## 👨💻 Mã giả
Trong ví dụ này, Observer giúp trình soạn thảo thông báo cho các đối tượng dịch vụ về các thay đổi trạng thái.

Danh sách các subscriber được biên dịch động: đối tượng có thể bắt đầu hoặc kết thúc lắng nghe thông báo khi đang chạy, dựa trên hành vi mong muốn của ứng dụng.
Trong triển khai này, lớp soạn thảo không duy trì danh sách đăng ký chính nó. Nó uỷ thác công việc cho đối tượng hỗ trợ đặc biệt làm điều đó. Bạn có thể nâng cấp đối tượng này để phục vụ như một trung tâm điều phối sự kiện, giúp bất kỳ đối tượng nào cũng hành động như một publisher.
Thêm các subscriber mới vào chương trình không yêu cầu thay đổi lớp publisher hiện có, miễn là chúng làm việc với subscriber thông qua cùng interface.
```c
// Lớp publisher cơ sở bao gồm code quản lý đăng ký
// và phương thức thông báo.
class EventManager is
private field listeners: hash map of event types and listeners
method subscribe(eventType, listener) is
listeners.add(eventType, listener)
method unsubscribe(eventType, listener) is
listeners.remove(eventType, listener)
method notify(eventType, data) is
foreach (listener in listeners.of(eventType)) do
listener.update(data)
// Publisher cụ thể bao gồm logic nghiệp vụ thực hấp dẫn một vài
// subscriber. Ta có thể có dẫn xuất lớp này từ một publisher cơ
// sở, nhưng điều này không luôn khả thi vì thực tế publisher cụ
// thể sẽ có lớp con. Trong trường hợp này, ta có thể vá logic
// đăng ký với composition.
class Editor is
public field events: EventManager
private field file: File
constructor Editor() is
events = new EventManager()
// Phương thức logic nghiệp vụ có thể thông báo subscriber
// về các thay đổi.
method openFile(path) is
this.file = new File(path)
events.notify("open", file.name)
method saveFile() is
file.write()
events.notify("save", file.name)
// ...
// Đây là interface subscriber. Nếu ngôn ngữ lập trình của bạn
// hỗ trợ kiểu function, bạn có thể thay thay toàn bộ hệ thống
// phân cấp subscriber với một tập hợp function.
interface EventListener is
method update(filename)
// Subscriber cụ thể phản ứng với bản cập nhật được phát hành
// bởi publisher mà chúng được gắn.
class LoggingListener implements EventListener is
private field log: File
private field message: string
constructor LoggingListener(log_filename, message) is
this.log = new File(log_filename)
this.message = message
method update(filename) is
log.write(replace('%s',filename,message))
class EmailAlertsListener implements EventListener is
private field email: string
private field message: string
constructor EmailAlertsListener(email, message) is
this.email = email
this.message = message
method update(filename) is
system.email(email, replace('%s',filename,message))
// Ứng dụng có thể cấu hình publisher và subscriber khi đang chạy
class Application is
method config() is
editor = new Editor()
logger = new LoggingListener(
"/path/to/log.txt",
"Someone has opened the file: %s")
editor.events.subscribe("open", logger)
emailAlerts = new EmailAlertsListener(
"admin@example.com",
"Someone has changed the file: %s")
editor.events.subscribe("save", emailAlerts)
```
## 💡 Ứng dụng
**🐞 Sử dụng Observer khi thay đổi trạng thái của một đối tượng có thể yêu cầu thay đổi đối tượng khác, và tập hợp thực của đối tượng là không biết trước hoặc có thể thay đổi động**
⚡ Bạn có thể gặp vấn đề này khi làm việc với lớp giao diện người dùng. Ví dụ, bạn tạo nhiều lớp button tuỳ chỉnh, và bạn muốn client kết nối với một vài tuỳ chỉnh code button của bạn để nó kích hoạt bất cứ khi nào người dùng click.
Observer giúp bất kỳ đối tượng nào triển khai interface subscriber đăng ký nhận thông báo sự kiện ở đối tượng publisher. Bạn có thể thêm cơ chế subscription cho button của bạn, giúp client kết nối với code tuỳ chỉnh thông qua lớp subscriber tuỳ chỉnh.
**🐞 Sử dụng Observer khi một vài đối tượng trong ứng dụng phải quan sát đối tượng khác, nhưng chỉ giới hạn thời gian và trường hợp cụ thể**
⚡ Danh sách đăng ký là động, nên subscriber có thể tham gia hoặc rời danh sách khi chúng cần.
## 📋 Triển khai
1. Nhìn qua logic nghiệp vụ và chia nó làm hai phần: phần chức năng cốt lỗi độc lập với các phần khác, sẽ hành động như publisher. Phần còn lại sẽ là tập hợp lớp subscriber.
2. Khai báo interface subscriber. Ở mức tối thiếu, nó nên có một phương thức cập nhật duy nhất.
3. Khai báo interface publisher và mô tả một cặp phương thức cho thêm và xoá đối tượng subscriber khỏi danh sách. Hãy nhớ publisher phải làm việc với subscriber thông qua interface subscriber.
4. Quyết định nơi đặt danh sách đăng ký và triển khai phương thức đăng ký. Thông thường, code này như nhau với tất cả kiểu publisher, thế nên nơi rõ ràng để đặt nó là lớp trừu tượng được lấy trực tiếp từ interface publisher. Publisher cụ thể mở rộng từ lớp này, kế thừa các hành vi đăng ký.
Tuy nhiên, nếu bạn áp dụng pattern với hệ phân cấp lớp hiện có, bao gồm cách tiếp cận dựa trên composition: đặt logic đăng ký vào đối tượng riêng biệt, và để cho tất cả publisher sử dụng nó.
5. Tạo lớp publisher cụ thể. Mỗi lần điều gì diễn ra trong publisher, sẽ phải thông báo cho tất cả subscriber.
6. Triển khai phương thức thông báo cập nhật ở lớp subscriber cụ thể. Hầu hết subscriber sẽ cần dữ liệu ngữ cảnh về sự kiện. Nó có thể được truyền như một tham số cho phương thức thông báo.
Nhưng ở đây ta có lựa chọn khác. Khi nhận thông báo, subscriber có thể tìm nạp dữ liệu trực tiếp từ thông báo. Trong trường hợp này, publisher phải truyền bản thân nó thông qua phương thức cập nhật. Các lựa chọn kém linh hoạt hơn là liên kết publisher với subscriber vĩnh viễn qua hàm khởi tạo.
7. Client phải tạo subscriber cần thiết và đăng ký nó với publisher phù hợp.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Open/Closed Principle*. Bạn có thể thêm lớp subscriber mới mà không ảnh hưởng đến code publisher (và ngược lại nếu có interface publisher).
✔️ Bạn có thể thiết lập quan hệ giữa các đối tượng khi đang chạy.
### Nhược điểm
❌ Subscriber được thông báo theo thứ tự ngẫu nhiên.
## 🔁 Quan hệ với các pattern khác
**Chain of Responsibility**, **Command**, **Mediator** và **Observer** giải quyết các cách khác nhau để kết nối người gửi và người nhận yêu cầu:
- **CoR** chuyển một yêu cầu tuần tự dọc theo một chuỗi động gồm những người nhận tiềm năng cho đến khi một trong số họ xử lý nó.
- **Command** thiết lập các kết nối một chiều giữa người gửi và người nhận.
- **Mediator** loại bỏ các kết nối trực tiếp giữa người gửi và người nhận, buộc họ phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- **Observer** cho phép người nhận đăng ký động và hủy đăng ký nhận yêu cầu.
Sự khác biệt giữa **Mediator** và **Observer** thường khó nắm bắt. Trong hầu hết các trường hợp, bạn có thể triển khai một trong các pattern này; nhưng đôi khi bạn có thể áp dụng đồng thời cả hai. Hãy xem chúng ta có thể làm điều đó như thế nào.
- Mục tiêu chính của **Mediator** là loại bỏ sự phụ thuộc lẫn nhau giữa một tập hợp các thành phần hệ thống. Thay vào đó, các thành phần này trở nên phụ thuộc vào một đối tượng mediator duy nhất. Mục tiêu của **Observer** là thiết lập các kết nối động một chiều giữa các đối tượng, nơi một số đối tượng đóng vai trò là cấp dưới của những đối tượng khác.
- Có một cách triển khai phổ biến của **Mediator** vào **Observer**. Đối tượng mediator đóng vai trò là publisher và các thành phần đóng vai trò là subscribers, đăng ký và hủy đăng ký tham gia các sự kiện của mediator. Khi **Mediator** được triển khai theo cách này, nó có thể trông rất giống với **Observer**.
- Nếu thấy bối rối, hãy nhớ rằng bạn có thể triển khai **Mediator** theo những cách khác. Ví dụ: bạn có thể liên kết vĩnh viễn tất cả các thành phần với cùng một đối tượng mediator. Việc triển khai này sẽ không giống với **Observer** nhưng vẫn sẽ là một bản sao của **Mediator**.
- Bây giờ hãy tưởng tượng một chương trình mà tất cả các thành phần đã trở thành publisher, cho phép các kết nối động với nhau. Sẽ không có đối tượng mediator tập trung, chỉ có một nhóm observer phân tán.
# Nguồn
[refactoring](https://refactoring.guru/design-patterns/observer)
================================================
FILE: behavioral-pattern/state/README.md
================================================
# State
## 📜 Mục đích
**State** là một design pattern thuộc nhóm behavoiral giúp chỉnh sửa hành vi của một đối tượng khi trạng thái bên trong nó thay đổi. Nó xảy ra nếu như một đối tượng thay đổi lớp của nó.

## 😟 Vấn đề
Pattern State có mối quan hệ gần gũi với khái niệm [Máy trạng thái hữu hạn](https://vi.wikipedia.org/wiki/Máy_trạng_thái_hữu_hạn) (gọi tắt là máy trạng thái)

Ý tưởng chính là như thế này, tại bất kỳ thời điểm nào cũng có một hữu hạn trạng thái mà chương trình có thể có. Với từng trạng thái đơn nhất, chương trình sẽ có hành vi khác nhau và chương trình còn có thể chuyển từ trạng thái này sang trạng thái khác ngay lập tức. Tuy nhiên, điều này phụ thuộc vào trạng thái hiện tại, mà chương trình có thể chuyển hoặc không thể chuyển sang trạng thái khác. Quy luật chuyển đổi này gọi là *transitions*, nó hữu hạn và có thể định trước.
Bạn có thể áp dụng cách tiếp cận này lên các đối tượng. Ví dụ bạn có lớp `Document`. Một tài liệu có thể có 3 trạng thái: `Draft`(nháp), `Moderation` (chờ duyệt) và `Published` (đã công khai). Phương thức `public` của tài liệu làm việc với từng trạng thái sẽ có vài khác biệt nhỏ:
- Ở `Draft`, nó chuyển tài liệu lên chờ duyệt.
- Ở `Moderation`, nó làm cho tài liệu công khai, nhưng chỉ khi người dùng hiện tại là admin.
- Ở `Publushed` nó không phải làm gì cả.

Máy trạng thái thường được triển khai với nhiều điều kiện hành động (`if` hoặc `switch`) để lựa chọn hành vi thích hợp dựa trên trạng thái hiện tại của đối tượng. Thông thường, "trạng thái" này chỉ là một tập hợp trường giá trị của đối tượng. Nếu bạn đã từng nghe về *Máy trạng thái hữu hạn* trước đây, thì bạn có lẽ đã triển khai nó ít nhất một lần. Ví dụ như nhìn đoạn code dưới đây bạn có thấy quen quen không?
```c
class Document is
field state: string
// ...
method publish() is
switch (state)
"draft":
state = "moderation"
break
"moderation":
if (currentUser.role == 'admin')
state = "published"
break
"published":
// Do nothing.
break
// ...
```
Điểm yếu lớn nhất của máy trạng thái nằm ở việc các điều kiện tự để lộ chúng khi ta thêm quá nhiều trạng thái và các hành vi phụ thuộc trạng thái vào lớp `Document`. Phần lớn phương thức sẽ chứa các điều kiện quái dị, để chọn hành vi phù hợp của phương thức theo trạng thái hiện tại. Điều này làm cho code trở nên khó bảo trì vì bất kỳ thay đổi nào đến logic transition sẽ đòi hỏi thay đổi điều kiện trạng thái ở toàn bộ phương thức.
Vấn đề có xu hướng trở nên lớn hơn khi dự án phát triển. Khá là khó khăn để có thể dự đoán tất cả trạng thái và transition xảy ra ở giai đoạn thiết kế. Do đó, một máy trạng thái tinh gọn được xây dựng với một tập hợp điều kiện giới hạn có thể phát triển thành một mớ hỗn độn theo thời gian.
## 😊 Giải pháp
State đề xuất giải pháp là tạo một lớp mới cho tất cả trạng thái của một đối tượng và trích xuất tất cả hành vi dựa trên trạng thái cụ thể vào lớp đó.
Thay vì triển khai tất cả hành vi của nó, đối tượng gốc bây giờ gọi là *context* sẽ lưu tham chiếu đến một trong những đối tượng trạng thái, để biểu diễn trạng thái hiện tại của nó và uỷ thác mọi công việc liên quan đến trạng thái cho đối tượng này.

Để chuyển context sang trạng thái khác, ta sẽ thay thế đối tượng trạng thái đang hoạt động với một đối tượng khác để có trạng thái mới. Điều này chỉ khả thi khi tất cả lớp trạng thái theo cùng một interface và context làm việc với các đối tượng đó thông qua interface này.
Cấu trúc này trông giống Strategy, nhưng có một điểm khác biệt. Ở State, các trạng thái cụ thể có thể biết về nhau và bắt đầu chuyển đổi từ trạng thái này sang trạng thái khác, trong khi các Stategy hầu như không bao giờ biết về nhau
## 🚗 Thế Giới Thực
Các button và switch trong điện thoại thông minh của bạn hoạt động khác nhau tùy thuộc vào trạng thái hiện tại của thiết bị:
- Khi điện thoại được mở khóa, việc nhấn các button dẫn đến việc thực hiện các chức năng khác nhau.
- Khi điện thoại bị khóa, nhấn bất kỳ button nào sẽ dẫn đến màn hình mở khóa.
- Khi điện thoại gần hết pin, nhấn bất kỳ button nào sẽ hiển thị màn hình sạc.
## 🏢 Cấu trúc

1. **Context** lưu trữ một tham chiếu đến một trong các đối tượng concrete state và uỷ thác cho nó tất cả công việc cụ thể liên quan đến trạng thái. Context giao tiếp với đối tượng state thông qua interface state. Context để lộ một setter nhằm truyền vào nó một đối tượng state mới.
2. **State** là interface khai báo phương thức cụ thể liên quan đến trạng thái. Phương thức này nên có nghĩa với tất cả concrete state vì bạn không muốn các trạng thái của bạn có một phương thức vô dụng không bao giờ dùng đến.
3. **Concrete State** cung cấp triển khai của nó cho phương thức cụ thể liên quan đến trạng thái. Để tránh trùng lặp với code trên nhiều state, bạn nên cung cấp lớp trừu tượng trung gian cho đóng gói các hành vi dùng chung.
Đối tượng state có thể lưu trữ một tham chiếu trở lại (backreference) đến đối tượng context. Thông qua tham chiếu này, state có thể tìm nạp thông tin cần thiết từ đối tượng context, cũng như bắt đầu chuyển trạng thái.
4. Cả context và concrete state có thể thiết lập trạng thái tiếp theo cho context và thực hiện chuyển đổi trạng thái thực bằng cách thay thế đối tượng state được liên kết với context.
## 👨💻 Mã giả
Trong ví dụ này, State sẽ làm cho cùng một bộ điều chỉnh nhạc có các hành vi khác nhau phụ thuộc vào trạng thái phát hiện tại.

Đối tượng chính của bộ phát nhạc có liên kết đến một đối tượng state, thứ thực hiện phần lớn công việc thực. Các hành động thay thế đối tượng state hiện tại của bộ phát nhạc bằng đối tượng khác, để thay đổi cách mà bộ phát nhạc phản ứng với tương tác của người dùng.
```c
// Lớp AudioPlayer hành động như một context. Nó luôn
// duy trì tham chiếu đến một trong số các lớp state
// để biểu diễn trạng thái hiện tại của bộ phát nhạc.
class AudioPlayer is
field state: State
field UI, volume, playlist, currentSong
constructor AudioPlayer() is
this.state = new ReadyState(this)
// Context uỷ thác việc xử lý đầu vào của người dùng
// cho đối tượng state. Kết quả dựa trên trạng thái
// hiện tại đang hoạt động, vì ở mỗi trạng thái sẽ xử
// lý đầu vào khác nhau.
UI = new UserInterface()
UI.lockButton.onClick(this.clickLock)
UI.playButton.onClick(this.clickPlay)
UI.nextButton.onClick(this.clickNext)
UI.prevButton.onClick(this.clickPrevious)
// Đối tượng khác có thể chuyển trạng thái hoạt động
// của bộ phát nhạc.
method changeState(state: State) is
this.state = state
// Các phương thức UI uỷ thác thực thi cho trạng thái
// đang hoạt động.
method clickLock() is
state.clickLock()
method clickPlay() is
state.clickPlay()
method clickNext() is
state.clickNext()
method clickPrevious() is
state.clickPrevious()
// State có thể gọi các phương thức dịch vụ có
// trên context
method startPlayback() is
// ...
method stopPlayback() is
// ...
method nextSong() is
// ...
method previousSong() is
// ...
method fastForward(time) is
// ...
method rewind(time) is
// ...
// Lớp state cơ sở khai báo các phương thức cho tất cả concrete
// state triển khai và cung cấp một tham chiếu trở về đối tượng
// context được liên kết với state. Các state có thể dùng tham chiếu
// đó để chuyển đổi trạng thái.
abstract class State is
protected field player: AudioPlayer
// Context truyền chính nó qua hàm khởi tạo của state. Điều
// này giúp state lấy được dữ liệu hữu ích khi cần.
constructor State(player) is
this.player = player
abstract method clickLock()
abstract method clickPlay()
abstract method clickNext()
abstract method clickPrevious()
// Các concrete state triển khai các hành vi khác nhau được
// liên kết với state của context.
class LockedState extends State is
// Khi bạn mở khoá một bộ phát nhạc bị khoá,
// nó có thể có một trong hai trạng thái.
method clickLock() is
if (player.playing)
player.changeState(new PlayingState(player))
else
player.changeState(new ReadyState(player))
method clickPlay() is
// Bị khoá, nên không làm gì cả.
method clickNext() is
// Bị khoá, nên không làm gì cả.
method clickPrevious() is
// Bị khoá, nên không làm gì cả.
// Chúng cũng có thể kích hoạt chuyển đổi trạng thái context.
class ReadyState extends State is
method clickLock() is
player.changeState(new LockedState(player))
method clickPlay() is
player.startPlayback()
player.changeState(new PlayingState(player))
method clickNext() is
player.nextSong()
method clickPrevious() is
player.previousSong()
class PlayingState extends State is
method clickLock() is
player.changeState(new LockedState(player))
method clickPlay() is
player.stopPlayback()
player.changeState(new ReadyState(player))
method clickNext() is
if (event.doubleclick)
player.nextSong()
else
player.fastForward(5)
method clickPrevious() is
if (event.doubleclick)
player.previous()
else
player.rewind(5)
```
## 💡 Ứng dụng
**🐞 Sử dụng State khi bạn có một đối tượng có các hành vi khác nhau phụ thuộc vào trạng thái hiện tại, số lượng trạng thái là rất lớn và code của trạng thái cụ thể thường xuyên thay đổi**.
⚡ Pattern đề nghị việc trích xuất tất cả code trạng thái cụ thể vào một tập hợp lớp riêng biệt. Kết quả là bạn có thể thêm trạng thái mới hoặc thay đổi cái đã có độc lập với nhau, giảm thiểu chi phí bảo trì.
**🐞 Sử dụng State khi bạn có một lớp với số lượng điều kiện không lồ để thay đổi hành vi lớp đó theo giá trị hiện tại của các trường trong lớp đó.**
⚡ State giúp bạn trích xuất các nhánh của các điều kiện này thành các phương thức của các lớp trạng thái tương ứng. Đồng thời bạn còn có thể làm sạch các trường tạm thời và các phương thức trợ giúp liên quan đến code trạng thái cụ thể khỏi lớp chính của bạn.
**🐞 Sử dụng State khi bạn có một lượng lớn code trùng lặp các trạng thái và chuyển đổi tương tự của máy trạng thái dựa trên điều kiện.**
⚡ State giúp bạn soạn các hệ thống phân cấp của các lớp trạng thái và làm giảm sự trùng lặp bằng cách trích xuất code chung vào lớp cơ sở trừu tượng.
## 📋 Triển khai
1. Xác định lớp nào sẽ hành động như context. Nó có thể là một lớp đã có sẵn hoặc một lớp mới, nếu code trạng thái cụ thể được phân phối trên nhiều lớp.
2. Với tất cả trạng thái thực, tạo một lớp dẫn xuất từ interface state. Sau đó đi qua tất cả phương thức của context, trích xuất mọi code liên quan đến trạng thái vào lớp mới vừa tạo.
3. Trong khi chuyển code vào lớp trạng thái, bạn sẽ gặp trường hợp là nó phụ thuộc vào thành phần riêng tư của context. Có một vài cách giải quyết là:
- Làm cho trường hay phương thức đó công khai.
- Chuyển hành vi bạn đang trích xuất vào phương thức công khai trong context và gọi nó từ lớp state. Cách này khá tệ nhưng nhanh bạn có thể sửa lại sau.
- Lồng lớp state vào lớp context, nhưng chỉ khi ngôn ngữ lập trình của bạn hỗ trợ lớp lồng nhau.
4. Trong lớp context, thêm trường tham chiếu của kiểu interface state và một setter công khai cho phép ghi đè giá trị lên trường.
5. Đi qua phương thức của context lần nữa và thay thế điều kiện trạng thái trống với lệnh gọi đến phương thức phù hợp của đối tượng state.
6. Để chuyển đổi trạng thái context, tạo một trong những lớp state và truyền nó vào context. Bạn có thể làm điều này bên trong context hoặc các state khác, hoặc ở client. Bất cứ khi nào thực hiện xong, lớp sẽ trở nên phụ thuộc vào lớp concrete state mà nó khởi tạo.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Single Responsibility Principle*. Tổ chức code liên kết với trạng thái cụ thể trong lớp riêng biệt.
✔️ *Open/Closed Principle*. Thêm trạng thái mới mà không ảnh hưởng đến lớp trạng thái hiện có hay ngữ cảnh.
✔️ Đơn giản hoá code context bằng loại bỏ các điều kiện máy trạng thái cồng kềnh.
### Nhược điểm
❌ Việc áp dụng pattern có thể quá mức cần thiết nếu máy trạng thái chỉ có một vài trạng thái hoặc hiếm khi thay đổi.
## 🔁 Quan hệ với các pattern khác
**Bridge**, **State**, **Strategy** (và ở một mức độ nào đó là **Adapter**) có cấu trúc rất giống nhau. Thật vậy, tất cả các pattern này đều dựa trên nguyên tắc là ủy thác công việc cho các đối tượng khác. Tuy nhiên, chúng giải quyết các vấn đề khác nhau. Một pattern không chỉ là một công thức để cấu trúc code của bạn theo một cách cụ thể. Nó còn có thể truyền đạt đến các dev khác về vấn đề mà pattern giải quyết.
**State** có thể được coi là một phần mở rộng của **Strategy**. Cả hai pattern đều dựa trên kết hợp: chúng thay đổi hành vi của ngữ cảnh bằng cách ủy quyền một số công việc cho các đối tượng trợ giúp. **Strategy** làm cho các đối tượng này hoàn toàn độc lập và không biết về nhau. Tuy nhiên, **State** không hạn chế sự phụ thuộc giữa các trạng thái cụ thể, cho phép chúng thay đổi trạng thái của ngữ cảnh theo ý muốn.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/state)
================================================
FILE: behavioral-pattern/strategy/README.md
================================================
# Strategy
## 📜 Mục đích
**Strategy** là một design pattern thuộc nhóm behavioral giúp bạn xác định một nhóm thuật toán, đặt chúng vào một lớp riêng biệt và làm cho các đối tượng của chúng có thể hoán đổi lẫn nhau.

## 😟 Vấn đề
Vào một ngày đẹp trời, bạn định tạo một ứng dụng chỉ đường cho các khách du lịch. Ứng dụng xoay quanh các bản đồ đẹp mắt giúp người dùng dễ dàng đi đến bất cứ thành phố nào.
Phần lớn chức năng yêu cầu của ứng dụng là tự thiết lập lộ trình đường đi. Người dùng sẽ nhập vào địa chỉ hiện tại của họ và thấy con đường nhanh nhất để đến đích trên bản đồ.
Phiên bản đầu tiên của ứng dụng chỉ tập trung vào những đại lộ. Những người du lịch bằng xe sẽ cảm thấy vui sướng vì điều này. Nhưng mà rõ ràng là, không phải tất cả mọi người đều du lịch bằng xe. Thế nên ở bản cập nhật tiếp theo, bạn thêm tính năng chức năng cho người đi bộ. Ngay sau đó, bạn thêm các lựa chọn khác cho những phương tiện công cộng(bus, tàu điện ngầm,..) trên tuyến đường của họ.
Tuy nhiên, mọi thứ vẫn chưa dừng lại. Sau đó bạn định thêm lộ trình cho người đi xe đạp, hay là về sau này bạn sẽ thêm các lựa chọn khác cho xây dựng các lộ trình qua tất cả điểm tham quan trong thành phố.

Từ quan điểm kinh doanh, ứng dụng của bạn đã thành công, nhưng ở khía cạnh kỹ thuật bạn sẽ gặp nhiều vấn đề đau đầu. Mỗi lần bạn thêm một thuật toán chỉ đường mới, lớp chính của bộ chỉ đường sẽ gấp đôi kích thước. Và đến một thời điểm nào đó, nó sẽ như là một con quái vật, cực kỳ khó cho việc bảo trì.
Bất kỳ một thuật toán nào thay đổi, cho dù chỉ là fix lỗi đơn giản hay một chút điều chỉnh lên các con đường nó cũng ảnh hưởng đến toàn bộ lớp, làm tăng nguy cơ sinh lỗi ở các đoạn code đã hoạt động.
Bên cạnh đó, teamwork cũng bất tiện hơn. Các đồng nghiệp của bạn, những người gia nhập sau khi phiên bản đầu tiên phát hành sẽ than phiền rằng họ mất quá nhiều thời gian cho giải quyết các xung đột khi hợp nhất. Triển khai tính năng mới yêu cầu thay đổi cùng một lớp khổng lồ, xung đột với code được viết bởi những người khác.
## 😊 Giải pháp
Strategy đề xuất giải pháp là bạn nên chọn một lớp làm điều gì đó cụ thể theo nhiều cách khác nhau và trích xuất tất cả thuật toán vào các lớp riêng biệt đấy gọi là *strategy*.
Lớp gốc gọi là context, phải có một trường lưu trữ tham chiếu đến một trong các stategy. Context uỷ thác công việc cho đối tượng strategy được liên kết thay vì tự thực hiện nó.
Context không có trách nhiệm chọn thuật toán phù hợp cho công việc. Thay vào đó, client truyền strategy mong muốn đến context. Thực tế, context không biết gì về strategy. Nó làm việc với mọi strategy thông qua interface chung, nó chỉ để lộ một phương thức duy nhất cho kích hoạt thuật toán đã đóng gói trong stategy được chọn.
Với cách này, context trở nên độc lập với các strategy cụ thể, bạn có thể thêm hay chỉnh sửa thuật toán mà không ảnh hưởng gì đến code của context hay các strategy khác.

Trở lại với ứng dụng chỉ đường, mội thuật toán định tuyến có thể được trích xuất vào lớp của chúng với phương thức `buildRoute` duy nhất. Phương thức nhận vào điểm đầu và đích đến, và trả về một tập hợp các trạm dừng của lộ trình.
Mặc dùng cho cùng một tham số, mỗi lớp định tuyến sẽ có tạo một lộ trình khác nhau, lớp chính của ứng dụng không thực sự quan tâm thuật toán được chọn vì công việc chính của nó chỉ là hiển thị các trạm dừng trên bản đồ. Lớp có phương thức chuyển đổi các lịch trình đang hoạt động, thế nên người dùng với các button ở giao diện người dùng, có thể thay thế hành vi được chọn hiện tại với cái khác.
## 🚗 Thế Giới Thực

Tưởng tượng để đi đến sân bay. Bạn có thể bắt xe bus, gọi taxi hay đi xe đập. Các phương tiện của bạn là strategy. Bạn có thể chọn một trong các strategy dựa vào các nhân tố như ví tiền hay thời gian.
## 🏢 Cấu trúc

1. **Context** duy trì một tham chiếu đến một trong các strategy cụ thể và giao tiếp với các đối tượng này thông qua interface strategy.
2. **Strategy** là interface chung cho tất cả strategy cụ thể. Nó khai báo một phương thức duy nhất cho context sử dụng để thực thi.
3. **Concrete Strategies** triển khai khác nhau của thuật toán mà context sử dụng.
4. Context gọi phương thức thực thi đến đối tượng strategy được liên kết mỗi lần nó cần chạy thuật toán. Context không cần biết chính xác kiểu strategy nào đang làm việc và thuật toán được thực thi thế nào.
5. **Client** tạo đối tượng strategy cụ thể và truyền nó vào context. Context để lộ một setter cho client thay thế với strategy được liên kết với context khi đang chạy.
## 👨💻 Mã giả
Trong ví dụ này, context sử dụng nhiều strategy để thực hiện các phép toán khác nhau.
```c
// Interface strategy khai báo các phép toán chung cho tất cả
// phiên bản hỗ trợ của một vài thuật toán. Context sử dụng
// interface này để gọi thuật toán đã xác định bởi concrete
// strategies.
interface Strategy is
method execute(a, b)
// Concrete strategies triển khai thuật toán khi đang theo
// interface strategy cơ sở. Interface hoán đổi chúng với
// nhau trong context.
class ConcreteStrategyAdd implements Strategy is
method execute(a, b) is
return a + b
class ConcreteStrategySubtract implements Strategy is
method execute(a, b) is
return a - b
class ConcreteStrategyMultiply implements Strategy is
method execute(a, b) is
return a * b
// Context xác định interface mà client mong muốn.
class Context is
// Context duy trì một tham chiếu đến một trong các đối tượng
// strategy. Context không biết rõ lớp cụ thể của strategy.
// Nó làm việc với mọi strategy thông qua interface strategy.
private strategy: Strategy
// Thông thường, context nhận strategy thông qua hàm khởi
// tạo và cung cập một setter cho strategy có thể chuyển
// đổi khi đang chạy.
method setStrategy(Strategy strategy) is
this.strategy = strategy
// Context uỷ thác công việc cho đối tượng strategy thay
// vì triển khai nhiều phiên bản thuật toán của chính nó.
method executeStrategy(int a, int b) is
return strategy.execute(a, b)
// Code client chọn một concrete strategy và truyền nó vào
// context. Client nên nhận thức được sự khác nhau giữa
// các strategy theo trật tự để chọn đúng.
class ExampleApplication is
method main() is
Create context object.
Read first number.
Read last number.
Read the desired action from user input.
if (action == addition) then
context.setStrategy(new ConcreteStrategyAdd())
if (action == subtraction) then
context.setStrategy(new ConcreteStrategySubtract())
if (action == multiplication) then
context.setStrategy(new ConcreteStrategyMultiply())
result = context.executeStrategy(First number, Second number)
Print result.
```
## 💡 Ứng dụng
**🐞 Sử dụng Strategy khi bạn muốn dùng các biến thể thuật toán khác nhau trong một đối tượng cho phép chuyển đổi từ thuật toán này sang thuật toán khác khi đang chạy**.
⚡ Strategy giúp bạn gián tiếp chỉnh sửa hành vi của đối tượng khi đang chạy bằng liên kết với các đối tượng con khác để thực hiện hành vi cụ thể theo các cách khác nhau.
**🐞 Sử dụng Strategy khi bạn có nhiều lớp giống nhau chỉ khác nhau cách chúng thực hiện một vài hành vi**
⚡ Strategy giúp bạn trích xuất các hành vi khác nhau vào một hệ thống phân cấp lớp và kết hợp với lớp gốc thành một, bằng cách này sẽ làm giảm code trùng lặp.
**🐞 Sử dụng Strategy để cô lập logic nghiệp vụ của một lớp khỏi triển khai chi tiết của thuật toán, thứ không mấy quan trọng trong ngữ cảnh của logic đó**.
⚡ Strategy giúp bạn cô lập code, dữ liệu bên trong và các phụ thuộc vào thuật toán với phần code còn lại. Các client khác nhau nhận về một interface đơn giản để thực thi thuật toán và chuyển đổi chúng khi đang chạy.
**🐞 Sử dụng Strategy khi lớp của bạn có một lượng điều kiện khổng lồ để chuyển đổi các biến thể khác nhau với cùng thuật toán**.
⚡ Strategy giúp bạn bỏ đi các điều kiện bằng cách trích xuất tất cả thuật toán vào các lớp riêng biệt. Toàn bộ triển khai cùng interface. Đối tượng gốc uỷ thác thực thi cho một trong các đối tượng trên thay vì triển khai tất cả biến thể của thuật toán.
## 📋 Triển khai
1. Trong lớp context, xác định thuật toán dễ thay đổi. Nó còn có thể có một lượng lớn điều kiện để chọn và thực thi một biến thể của cùng một thuật toán khi đang chạy
2. Khai báo interface strategy chung cho tất cả biến thể của thuật toán.
3. Từng cái một, trích xuất tất cả thuật toán vào các lớp của nó. Chúng nên triển khai tất cả trên interface strategy.
4. Trong lớp context, thêm một trường cho lưu trữ tham chiếu đến đối tượng strategy. Cung cấp một setter cho thay thế giá trị của trường này. Context nên làm việc với đối tượng strategy thông qua interface strategy. Context có thể định nghĩa một interface để cho phép strategy truy cập dữ liệu của nó.
5. Client của context phải liên kết nó với strategy phù hợp để ứng với cách chúng mong đợi context thực hiện hành vi chính.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn có thể chuyển đổi thuật toán bên trong đối tượng khi đang chạy.
✔️ Bạn có thể cô lập triển khai chi tiết của thuật toán khỏi code sử dụng nó.
✔️ Bạn có thể thay thế kế thừa với hỗn hợp.
✔️ *Open/Closed Principle*. Bạn có thể thêm strategy mới mà không ảnh hưởng đến context.
### Nhược điểm
❌ Nếu bạn chỉ có một vài thuật toán và chúng hiếm khi thay đổi, thì không có lý do thực sự nào để làm phức tạp chương trình quá mức với các lớp và interface mới đi kèm với pattern.
❌ Client phải nhận thức được các strategy khác nhau để có thể chọn cái phù hợp.
❌ Rất nhiều ngôn ngữ lập trình hiện đại có hỗ trợ kiểu hàm cho phép bạn triển khai các phiên bản khác nhau của thuật toán bên trong một tập hợp các hàm ẩn danh. Sau đó, bạn có thể sử dụng các chức năng này chính xác như khi bạn đã sử dụng các đối tượng strategy, nhưng không làm tăng code của bạn với các lớp và giao diện bổ sung.
## 🔁 Quan hệ với các pattern khác
**Bridge**, **State**, **Strategy** (và ở một mức độ nào đó là **Adapter**) có cấu trúc rất giống nhau. Thật vậy, tất cả các pattern này đều dựa trên nguyên tắc là ủy thác công việc cho các đối tượng khác. Tuy nhiên, chúng giải quyết các vấn đề khác nhau. Một pattern không chỉ là một công thức để cấu trúc code của bạn theo một cách cụ thể. Nó còn có thể truyền đạt đến các dev khác về vấn đề mà pattern giải quyết.
**Command** và **Strategy** có thể trông giống nhau vì bạn có thể sử dụng cả hai để tham số hóa một đối tượng bằng một số hành động. Tuy nhiên, chúng có mục đích rất khác nhau.
- Bạn có thể sử dụng **Command** để chuyển đổi bất kỳ thao tác nào thành một đối tượng. Các tham số của thao tác trở thành các trường của đối tượng đó. Việc chuyển đổi cho phép bạn trì hoãn việc thực hiện thao tác, xếp hàng đợi, lưu trữ lịch sử lệnh, gửi lệnh đến các dịch vụ từ xa, v.v.
- Mặt khác, **Strategy** thường mô tả các cách khác nhau để thực hiện cùng một việc, cho phép bạn hoán đổi các thuật toán này trong một lớp ngữ cảnh duy nhất.
**Decorator** cho phép bạn thay đổi vẻ ngoài của một đối tượng, trong khi **Strategy** cho phép bạn thay đổi ruột.
**Template Method** dựa trên sự kế thừa: nó cho phép bạn thay đổi các phần của một thuật toán bằng cách mở rộng các phần đó trong các lớp con. **Strategy** dựa trên cấu tạo: bạn có thể thay đổi các phần trong hành vi của đối tượng bằng cách cung cấp cho đối tượng các strategy khác nhau tương ứng với hành vi đó. **Template Method** hoạt động ở cấp độ lớp, vì vậy nó là tĩnh. **Strategy** hoạt động ở cấp độ đối tượng, cho phép bạn chuyển đổi hành vi trong thời gian chạy.
**State** có thể được coi là một phần mở rộng của **Strategy**. Cả hai pattern đều dựa trên kết hợp: chúng thay đổi hành vi của ngữ cảnh bằng cách ủy quyền một số công việc cho các đối tượng trợ giúp. **Strategy** làm cho các đối tượng này hoàn toàn độc lập và không biết về nhau. Tuy nhiên, **State** không hạn chế sự phụ thuộc giữa các trạng thái cụ thể, cho phép chúng thay đổi trạng thái của ngữ cảnh theo ý muốn.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/strategy)
================================================
FILE: behavioral-pattern/template-method/README.md
================================================
# Template Method
## 📜 Mục đích
**Template Method** là một design pattern thuộc nhóm behavioral giúp định nghĩa bộ khung của thuật toán ở lớp cha (superclass) nhưng các lớp con (subsclasses) có thể ghi đè lên các bước cụ thể của thuật toán mà không làm thay đổi cấu trúc của nó.

## 😟 Vấn đề
Tưởng tượng bạn đang tạo một ứng dụng khai thác dữ liệu để phân tích tài liệu của công ty. Người dùng cung cấp các tài liệu cho ứng dụng với các định dạng khác nhau (PDF, DOC, CSV), ứng dụng sẽ trích xuất dữ liệu có ích từ các tài liệu này ở một định dạng thống nhất.
Phiên bản đầu tiên của ứng dụng chỉ làm việc với file DOC. Trong phiên bản tiếp theo nó hỗ trợ file CSV. Và một tháng sau, nó trích xuất cả dữ liệu từ file PDF.

Vào một thời điểm nào đó, bạn nhận thấy rằng cả code ở cả ba lớp có rất nhiều điểm tương đồng nhau. Mặc dù code để xử lý các định dạng dữ liệu khác nhau hoàn toàn khác nhau ở tất cả các lớp, nhưng code để xử lý và phân tích dữ liệu gần như giống hệt nhau. Sẽ rất tuyệt vời nếu ta có thể loại bỏ sự trùng lặp code nhưng vẫn giữ nguyên được cấu trúc của thuật toán.
Và một vấn đề khác nữa liên quan đến code client, nơi sử dụng các lớp này, là nó có rất nhiều điều kiện để chọn quá trình hành động thích hợp tùy thuộc vào lớp của đối tượng xử lý. Nếu cả ba lớp xử lý đều có một interface chung hoặc một lớp cơ sở, bạn có thể loại bỏ các điều kiện trong code client và sử dụng tính đa hình khi gọi các phương thức trên một đối tượng xử lý.
## 😊 Giải pháp
Template Method gợi ý rằng bạn nên chia nhỏ thuật toán thành một chuỗi các bước, biến các bước này thành các phương thức và đặt một loạt lệnh gọi đến các phương thức này bên trong một phương thức template duy nhất. Các bước có thể là `abstract` (trừu tượng) hoặc có một số triển khai mặc định. Để sử dụng thuật toán, client phải cung cấp lớp con của chính nó, thực hiện tất cả các bước trừu tượng và ghi đè một số bước tùy chọn nếu cần (nhưng không được ghi lên phương thức template).
Hãy xem cách nó làm việc trong ứng dụng khai thác dữ liệu. Ta có thể tạo một lớp cơ sở cho cả ba thuật toán phân tích. Lớp này định nghĩa một phương thức template bao gồm một loạt các lệnh gọi đến các bước xử lý tài liệu khác nhau.

Lúc đầu, ta có thể khai báo tất cả các bước là `abstract`, buộc các lớp con cung cấp các triển khai riêng của chúng cho các phương thức này. Trong trường hợp này, các lớp con đã có tất cả các triển khai cần thiết, vì vậy điều duy nhất ta cần làm là điều chỉnh signature của các phương thức để phù hợp với các phương thức của lớp cha.
Bây giờ, hãy xem cách để có thể loại bỏ code trùng lặp. Có thể thấy code để mở/đóng file và trích xuất/phân tích dữ liệu là khác nhau đối với các định dạng dữ liệu khác nhau, vì vậy bạn không cần phải đụng đến các phương pháp đó. Tuy nhiên, việc thực hiện các bước khác, chẳng hạn như phân tích dữ liệu raw và soạn báo cáo, rất giống nhau, vì vậy nó có thể được kéo lên lớp cơ sở, nơi các lớp con có thể chia sẻ code đó.
Như bạn có thể thấy, ta có hai loại bước:
- các bước trừu tượng phải được thực hiện bởi mọi lớp con.
- các bước tùy chọn đã có một số triển khai mặc định, nhưng vẫn có thể bị ghi đè nếu cần.
Có một loại bước khác, được gọi là hook. Hook là một bước tùy chọn với phần thân trống. Phương thức template sẽ hoạt động ngay cả khi hook không bị ghi đè. Thông thường, các hook được đặt trước và sau các bước quan trọng của thuật toán, cung cấp các lớp con với các điểm mở rộng bổ sung cho một thuật toán.
## 🚗 Thế Giới Thực

Phương pháp template có thể được sử dụng trong xây dựng hàng loạt ngôi nhà. Kế hoạch kiến trúc để xây dựng một ngôi nhà tiêu chuẩn có thể chứa một số điểm mở rộng cho phép người chủ sở hữu có tiềm năng điều chỉnh một số chi tiết của ngôi nhà.
Mỗi công đoạn xây dựng như đổ móng, đóng khung, xây tường, lắp đặt hệ thống ống nước, đi dây điện nước,… đều có thể thay đổi đôi chút để tạo cho ngôi nhà có một chút khác biệt so với những ngôi nhà khác.
## 🏢 Cấu trúc

1. **Abstract Class** là lớp trừu tượng khai báo các phương thức hoạt động như các bước của một thuật toán, cũng như phương thức template để gọi các phương thức này theo một thứ tự cụ thể. Các bước có thể được khai báo là trừu tượng hoặc có một số triển khai mặc định.
2. **Concrete Classes** có thể ghi đè tất cả các bước, nhưng không thể ghi đè lên phương thức template.
## 👨💻 Mã giả
Trong ví dụ này, phương thức Template cung cấp một "bộ khung" cho các branch khác nhau của trí thông minh nhân tạo trên một trò chơi điện tử mô phỏng đơn giản.

Tất cả chủng tộc trong trò chơi gần như giống nhau về kiểu unit và cách xây dựng. Do đó bạn có thể sử dụng lại cùng một cấu trúc AI cho các chủng tộc khác nhau, đồng thời vẫn có thể ghi đè lên một vài chi tiết. Với cách tiếp cận này, bạn có thể ghi đè lên AI của loài orc làm cho chúng hung dữ, làm cho loài người có khả năng phòng thủ và lũ quái vật không thể xây dựng bất kỳ thứ gì. Thêm một chủng tộc mới trong game yêu cầu tạo một lớp con AI mới và ghi đè lên phương thức mặc định đã tạo ở lớp AI cơ sở.
```c
// Lớp abstract định nghĩa một phương thức template bao gồm
// bộ khung của một vài thuật toán được gọi, thông thường là
// các thao tác nguyên thuỷ trừu tượng. Concrete subclass triển
// khai các thao tác này, nhưng vẫn giữ nguyên phương thức
// template.
class GameAI is
// Phương thức template định nghĩa khung của một thuật toán.
method turn() is
collectResources()
buildStructures()
buildUnits()
attack()
// Một vài bước có thể triển khai ở tại lớp cơ sở.
method collectResources() is
foreach (s in this.builtStructures) do
s.collect()
// Và một số có thể định nghĩa là trừu tượng.
abstract method buildStructures()
abstract method buildUnits()
// Một lớp có thể có nhiều phương thức template.
method attack() is
enemy = closestEnemy()
if (enemy == null)
sendScouts(map.center)
else
sendWarriors(enemy.position)
abstract method sendScouts(position)
abstract method sendWarriors(position)
// Concrete class phải triển khai tất cả thao tác trừu tượng
// của lớp cơ sở và không được ghi đè lên phương thức template.
class OrcsAI extends GameAI is
method buildStructures() is
if (there are some resources) then
// Xây dựng trang trại, sau đó là doanh trại, sau đó là thành trì.
method buildUnits() is
if (there are plenty of resources) then
if (there are no scouts)
// Xây dựng người liên lạc, thêm nó vào nhóm trinh sát.
else
// Xây dựng grunt, thêm nó vào nhóm chiến binh.
// ...
method sendScouts(position) is
if (scouts.length > 0) then
// Cử trinh sát đến vị trí.
method sendWarriors(position) is
if (warriors.length > 5) then
// Đưa chiến binh vào vị trí.
// Lớp con có thể ghi đè một vài thao tác với
// triển khai mặc định.
class MonstersAI extends GameAI is
method collectResources() is
// Quái vật không thể thu thập tài nguyên.
method buildStructures() is
// Quái vật không thể xây dựng kiến trúc..
method buildUnits() is
// Quái vật không thể xây dựng đơn vị.
```
## 💡 Ứng dụng
**🐞 Sử dụng phương thức Template khi bạn muốn client chỉ mở rộng các bước cụ thể của thuật toán chứ không phải toàn bộ cấu trúc của nó**
⚡ Phương thức Template giúp bạn chuyển một khối thuật toán thành một loạt các bước riêng rẽ để dễ mở rộng bởi lớp con trong khi vẫn giữ nguyên cấu trúc đã định nghĩa ở lớp cha.
**🐞 Sử dụng template khi bạn có nhiều lớp bao gồm các thuật toán giống nhau chỉ có một ít là khác biệt. Và bạn phải chỉnh sửa tất cả lớp khi thuật toán thay đổi**.
⚡ Khi bạn chuyển một thuật toán thành phương thức template, bạn có thể kéo các bước với triển khai giống nhau lên lớp cha, giảm thiểu code trùng lặp. Code khác nhau ở lớp con có thể được giữ lại ở đấy.
## 📋 Triển khai
1. Phân tích thuật toán mục tiêu để xem liệu bạn có thể chia nó thành các bước hay không. Xem xét bước nào là chung cho tất cả các lớp con và bước nào là duy nhất.
2. Tạo lớp trừu tường (`abstract`) và khai báo phương thức template và một tập hợp của phương thức trừu tượng để biểu diễn các bước của thuật toán. Phác thảo cấu trúc của thuật toán trong phương pháp template bằng cách thực hiện các bước tương ứng. Cân nhắc việc tạo phương thức template cuối cùng để ngăn các lớp con ghi đè nó.
3. Sẽ không sao nếu tất cả các bước đều trừu tượng. Tuy nhiên, một số bước có thể được hưởng lợi từ việc triển khai mặc định. Các lớp con không phải triển khai các phương thức đó.
4. Thêm hook giữa các bước cốt lõi của thuật toán.
5. Đối với mỗi biến thể của thuật toán, hãy tạo một lớp con cụ thể(concrete subclasses) mới. Nó phải triển khai tất cả các bước trừu tượng, nhưng cũng có thể ghi đè một số bước tùy chọn.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn chỉ cho phép client ghi đè một số phần nhất định của một thuật toán lớn, giúp chúng ít bị ảnh hưởng bởi những thay đổi xảy ra với các phần khác của thuật toán.
✔️ Bạn có thể gom code trùng lặp vào một lớp cha.
### Nhược điểm
❌ Một số client có thể bị giới hạn bởi khung thuật toán được cung cấp.
❌ Bạn có thể vi phạm Nguyên tắc Liskov Substitution, khi chặn triển khai bước mặc định thông qua một lớp con.
❌ Các phương pháp template có xu hướng khó bảo trì hơn khi chúng có nhiều bước hơn.
## 🔁 Quan hệ với các pattern khác
**Factory Method** là một chuyên môn hóa của **Template Method**. Đồng thời, **Factory Method** có thể đóng vai trò là một bước trong một **Template Method** lớn.
**Template Method** dựa trên sự kế thừa: nó cho phép bạn thay đổi các phần của một thuật toán bằng cách mở rộng các phần đó trong các lớp con. **Strategy** dựa trên cấu tạo: bạn có thể thay đổi các phần trong hành vi của đối tượng bằng cách cung cấp cho đối tượng các strategy khác nhau tương ứng với hành vi đó. **Template Method** hoạt động ở cấp độ lớp, vì vậy nó là tĩnh. **Strategy** hoạt động ở cấp độ đối tượng, cho phép bạn chuyển đổi hành vi trong thời gian chạy.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/template-method)
================================================
FILE: behavioral-pattern/visitor/README.md
================================================
# Visitor
## 📜 Mục đích
**Visitor** là một design pattern thuộc nhóm behavioral giúp bạn tách các thuật toán khỏi đối tượng mà chúng đang hoạt động trên đó.

## 😟 Vấn đề
Tưởng tượng team bạn đang phát triển một ứng dụng làm việc với thông tin địa lý được cấu trúc dưới dạng một đồ thị khổng lồ. Mỗi nút trong đồ thị có thể biểu diễn một thực thể phức tạp như một thành phố, nhưng chi tiết hơn như các nhà máy, khu tham quan,... Các nút được kết nối với nhau nếu có một con đường giữa các đối tượng thực mà nó biểu diễn. Hiểu sâu hơn, mỗi loại nút được biểu diễn bởi lớp riêng của nó, trong khi mỗi nút cụ thể là một đối tượng.

Tại một thời điểm nào đó, bạn có nhiệm vụ xuất đồ thị sang định dạng XML. Lúc đầu, công việc có vẻ khá đơn giản. Bạn đã lên kế hoạch thêm một phương thức xuất vào từng lớp nút và sau đó tận dụng đệ quy để đi qua từng nút của đồ thị, thực hiện phương thức xuất. Giải pháp rất đơn giản và gọn gàng: nhờ tính đa hình, bạn không phải ghép đoạn code phương thức xuất với các lớp nút cụ thể.
Thật không may, kỹ sư hệ thống đã từ chối cho phép bạn thay đổi các lớp nút hiện có. Anh ấy nói rằng code đã được tạo và anh ấy không muốn mạo hiểm phá vỡ nó vì một lỗi tiềm ẩn trong các thay đổi của bạn.

Bên cạnh đó, anh ấy đặt câu hỏi liệu có hợp lý khi có code xuất XML trong các lớp nút hay không. Công việc chính của các lớp này là làm việc với dữ liệu địa lý. Hành vi xuất XML sẽ có vẻ không phù hợp ở đó.
Có một lý do khác cho việc từ chối. Rất có thể sau khi tính năng này được triển khai, một người nào đó từ bộ phận tiếp thị sẽ yêu cầu bạn cung cấp khả năng xuất sang một định dạng khác hoặc yêu cầu một số thứ kỳ lạ khác. Điều này sẽ buộc bạn phải thay đổi những lớp này một lần nữa.
## 😊 Giải pháp
Pattern Visitor gợi ý rằng bạn nên đặt hành vi mới vào một lớp riêng biệt được gọi là visitor, thay vì cố gắng tích hợp nó vào các lớp hiện có. Đối tượng gốc phải thực hiện hành vi bây giờ được chuyển cho một trong những phương thức của visitor dưới dạng tham số, cung cấp cho phương thức này quyền truy cập vào tất cả dữ liệu cần thiết có trong đối tượng.
Bây giờ, điều gì sẽ xảy ra nếu hành vi đó có thể được thực thi trên các đối tượng của các lớp khác nhau? Ví dụ, trong trường hợp này là xuất XML, việc triển khai thực tế có thể sẽ khác một chút trên các lớp nút khác nhau. Do đó, lớp visitor phải xác định không phải một, mà là một tập hợp các phương thức, mỗi phương thức có thể nhận các tham số thuộc các kiểu khác nhau, như thế này:
```c
class ExportVisitor implements Visitor is
method doForCity(City c) { ... }
method doForIndustry(Industry f) { ... }
method doForSightSeeing(SightSeeing ss) { ... }
// ...
```
Nhưng chính xác thì chúng ta sẽ gọi những phương pháp này như thế nào, đặc biệt là khi xử lý toàn bộ đồ thị? Các phương pháp này có các signature khác nhau, vì vậy ta không thể sử dụng tính đa hình. Để chọn một phương thức visitor thích hợp có thể xử lý một đối tượng nhất định, ta cần kiểm tra lớp của nó.
```c
foreach (Node node in graph)
if (node instanceof City)
exportVisitor.doForCity((City) node)
if (node instanceof Industry)
exportVisitor.doForIndustry((Industry) node)
// ...
}
```
Bạn có thể hỏi, tại sao chúng ta không sử dụng phương thức overloading - nạp chồng? Overloading là khi bạn đặt cùng một tên cho tất cả các phương thức, ngay cả khi chúng có các tham số khác nhau. Thật không may, ngay cả trong trường hợp ngôn ngữ lập trình của ta hỗ trợ overloading (như Java và C #), thì nó cũng không giúp ích được gì cả. Vì lớp chính xác của đối tượng nút không được biết trước, cơ chế overloading sẽ không thể xác định phương thức chính xác để thực thi. Nó sẽ mặc định là phương thức nhận một đối tượng của lớp `Node` cơ sở.
Tuy nhiên, pattern visitor giải quyết vấn đề này. Nó sử dụng một kỹ thuật gọi là [**Double Dispatch**](https://refactoring.guru/design-patterns/visitor-double-dispatch), giúp thực thi phương thức thích hợp trên một đối tượng mà không cần các điều kiện rườm rà.
Và thay vì cho phép client chọn một phiên bản thích hợp của phương thức để gọi, tại sao ta không ủy thác lựa chọn này cho các đối tượng mà chúng ta đang chuyển cho visitor làm tham số ? Vì các đối tượng biết các lớp riêng của chúng, chúng có thể chọn một phương pháp thích hợp cho visitor một cách ít lúng túng hơn. Chúng "accept" một visitor và cho visitor đó biết phương thức truy cập nào nên được thực thi.
```c
// Client code
foreach (Node node in graph)
node.accept(exportVisitor)
// City
class City is
method accept(Visitor v) is
v.doForCity(this)
// ...
// Industry
class Industry is
method accept(Visitor v) is
v.doForIndustry(this)
// ...
```
Rốt cuộc thì ta cũng phải thay đổi các lớp nút. Nhưng ít nhất sự thay đổi là nhỏ và nó cho phép ta thêm các hành vi khác mà không phải thay đổi code một lần nữa.
Bây giờ, nếu ta trích xuất một interface chung cho tất cả visitor, thì tất cả các nút hiện có có thể hoạt động với bất kỳ visitor nào mà bạn thêm vào ứng dụng. Nếu bạn thấy mình đang thêm một hành vi mới liên quan đến các nút, tất cả những gì bạn phải làm là triển khai một lớp visitor mới.
## 🚗 Thế Giới Thực

Hãy tưởng tượng một đại lý bảo hiểm dày dạn kinh nghiệm đang mong muốn có được khách hàng mới. Anh ta có thể đến thăm mọi tòa nhà trong khu phố, cố gắng bán bảo hiểm cho mọi người anh ta gặp. Tùy thuộc vào loại hình tổ chức chiếm giữ tòa nhà, anh ta có thể đưa ra các chính sách bảo hiểm chuyên biệt:
- Nếu đó là một tòa nhà dân cư, anh ta bán bảo hiểm y tế.
- Nếu đó là một ngân hàng, anh ta bán bảo hiểm trộm cắp.
- Nếu đó là một quán cà phê, anh ấy bán bảo hiểm cháy nổ và thiên tai.
## 🏢 Cấu trúc

1. **Visitor** là interface khai báo một tập hợp các phương thức truy cập có thể lấy các concrete element của cấu trúc đối tượng làm tham số. Các phương thức này có thể trùng tên nếu chương trình được viết bằng ngôn ngữ hỗ trợ overloading, nhưng kiểu tham số của chúng phải khác nhau.
2. **Concrete Visitor** thực hiện một số phiên bản của các hành vi giống nhau, được điều chỉnh cho các lớp concrete element khác nhau.
3. **Element** là interface khai báo một phương thức để "accept" visitor. Phương thức này phải có một tham số được khai báo với kiểu interface visitor.
4. **Concrete Element** thực hiện phương pháp nghiệm thu. Mục đích của phương thức này là chuyển hướng lệnh gọi đến phương thức của visitor thích hợp tương ứng với lớp element hiện tại.
Cần biết rằng ngay cả khi một lớp element cơ sở triển khai phương thức này, tất cả các lớp con vẫn phải ghi đè phương thức này trong các lớp của chính chúng và gọi phương thức thích hợp trên đối tượng visitor.
5. **Client** thường đại diện cho một tập hợp hoặc một số đối tượng phức tạp khác (ví dụ, một cây tổng hợp). Thông thường, client không biết tất cả các lớp concrete element vì chúng làm việc với các đối tượng từ tập hợp đó thông qua một số interface trừu tượng
## 👨💻 Mã giả
Trong ví dụ này, Visitor thêm hỗ trợ xuất XML vào hệ thống phân cấp lớp của các hình dạng hình học.

*Xuất nhiều loại đối tượng khác nhau sang định dạng XML thông qua đối tượng visitor.*
```c
// Interface element khai báo phương thức `accept` để
// nhận interface visitor cơ sở như là tham số.
interface Shape is
method move(x, y)
method draw()
method accept(v: Visitor)
// Mỗi lớp concrete element phải triển khai phương
// thức `accept` theo một cách như gọi phương thức
// của visitor phù hợp với lớp của element.
class Dot implements Shape is
// ...
// Lưu ý ta gọi `visitDot`, tương ứng với tên lớp hiện
// tại. Cách này giúp visitor biết lớp của element
// đang làm việc với nó.
method accept(v: Visitor) is
v.visitDot(this)
class Circle implements Shape is
// ...
method accept(v: Visitor) is
v.visitCircle(this)
class Rectangle implements Shape is
// ...
method accept(v: Visitor) is
v.visitRectangle(this)
class CompoundShape implements Shape is
// ...
method accept(v: Visitor) is
v.visitCompoundShape(this)
// Interface visitor khai báo một tập hợp phương thức đi qua
// tương ứng với các lớp element. Ký hiệu của phương thức
// đi qua giúp visitior xác định chính xác lớp của element
// đang xử lý nó.
interface Visitor is
method visitDot(d: Dot)
method visitCircle(c: Circle)
method visitRectangle(r: Rectangle)
method visitCompoundShape(cs: CompoundShape)
// Concrete visitor triển khai nhiều phiên bản thuật toán
// giống nhau, thứ làm việc với tất cả lớp concrete element.
//
// Bạn có thể có nhiều lợi ích từ làm việc với pattern Visitor
// khi sử dụng nó với đối tượng có cấu trúc phức tạp như cây
// Composite. Trong trường hợp này, nó sẽ hữu ích để lưu trữ
// một vài trạng thái trung gian của thuật toán trong khi thực
// thi phương thức của visitor qua các đối tượng khác nhau của
// cấu trúc.
class XMLExportVisitor implements Visitor is
method visitDot(d: Dot) is
// Xuất ID của dấu chấm và hệ toạ độ trung tâm.
method visitCircle(c: Circle) is
// Xuất ID của vòng tròn, toạ độ trung tâm và bán kính.
method visitRectangle(r: Rectangle) is
// Xuất ID của hình chữ nhật, toạ độ trên-trái,
// chiều dài và chiều rộng.
method visitCompoundShape(cs: CompoundShape) is
// Xuất ID của hình dạng cũng như danh sách con của ID.
// Code client chạy thao tác visitor qua bất kỳ tập hợp element
// mà không cần biết lớp cụ thể của nó. Thao tá accept trực tiếp
// gọi đến thao tác thích hợp ở đối tượng visitor.
class Application is
field allShapes: array of Shapes
method export() is
exportVisitor = new XMLExportVisitor()
foreach (shape in allShapes) do
shape.accept(exportVisitor)
```
## 💡 Ứng dụng
**🐞 Sử dụng Visitor khi bạn cần thực hiện thao tác trên tất cả các phần tử của cấu trúc đối tượng phức tạp (ví dụ: cây đối tượng).**
⚡ Pattern Visitor cho phép bạn thực hiện một thao tác trên một tập hợp các đối tượng có các lớp khác nhau bằng cách để một đối tượng visitor triển khai một số biến thể của cùng một thao tác, tương ứng với tất cả các lớp mục tiêu.
**🐞 Sử dụng Visitor để làm sạch logic nghiệp vụ của các hành vi phụ trợ.**
⚡ Visitor cho phép bạn làm cho các lớp chính của ứng dụng tập trung hơn vào công việc chính của chúng bằng cách trích xuất tất cả các hành vi khác vào một tập hợp các lớp visitor.
**🐞 Sử dụng Visitor khi một hành vi chỉ có ý nghĩa trong một số lớp của hệ thống phân cấp lớp, nhưng không có ý nghĩa trong các lớp khác.**
⚡ Bạn có thể trích xuất hành vi này thành một lớp visitor riêng biệt và chỉ triển khai những phương thức truy cập chấp nhận các đối tượng của các lớp có liên quan, để trống phần còn lại.
## 📋 Triển khai
1. Khai báo interface visitor với một tập hợp các phương thức “ghé thăm”, một phương thức cho mỗi lớp phần tử cụ thể tồn tại trong chương trình.
2. Khai báo interface phần tử. Nếu bạn đang làm việc với hệ thống phân cấp lớp phần tử hiện có, hãy thêm phương thức trừu tượng "accept" vào lớp cơ sở của hệ thống phân cấp. Phương thức này phải chấp nhận một đối tượng visitor làm tham số.
3. Thực hiện các phương pháp chấp nhận trong tất cả các lớp phần tử cụ thể. Các phương thức này chỉ phải chuyển hướng cuộc gọi đến một phương thức thăm trên đối tượng visitor đến phù hợp với lớp của phần tử hiện tại.
4. Các lớp phần tử chỉ nên hoạt động với visitor thông qua interface visitor. Tuy nhiên, visitor phải biết tất cả các lớp phần tử cụ thể, được tham chiếu như các kiểu tham số của các phương thức truy cập.
5. Đối với mỗi hành vi không thể được triển khai bên trong phân cấp phần tử, hãy tạo một lớp visitor cụ thể mới và triển khai tất cả các phương pháp truy cập.
Bạn có thể gặp phải tình huống trong đó visitor sẽ cần quyền truy cập vào một số thành viên riêng tư của lớp phần tử. Trong trường hợp này, bạn có thể đặt các trường hoặc phương thức này ở chế độ công khai, vi phạm tính đóng gói của phần tử hoặc lồng lớp visitor vào lớp phần tử. Điều sau chỉ có thể thực hiện được nếu bạn may mắn làm việc với ngôn ngữ lập trình hỗ trợ các lớp lồng nhau.
6. Client phải tạo các đối tượng visitor và chuyển chúng vào các phần tử thông qua các phương thức "accept".
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ *Open/Closed Principle*. Bạn có thể thêm một hành vi mới có thể hoạt động với các đối tượng của các lớp khác nhau mà không cần thay đổi các lớp này.
✔️ *Single Responsibility Principle*. Bạn có thể chuyển nhiều phiên bản của cùng một hành vi vào cùng một lớp.
✔️ Một đối tượng visitor có thể tích lũy một số thông tin hữu ích khi làm việc với nhiều đối tượng khác nhau. Điều này có thể hữu ích khi bạn muốn duyệt qua một số cấu trúc đối tượng phức tạp, chẳng hạn như cây đối tượng và áp dụng visitor vào từng đối tượng của cấu trúc này.
### Nhược điểm
❌ Bạn cần cập nhật tất cả visitor mỗi khi một lớp được thêm vào hoặc xóa khỏi hệ thống phân cấp phần tử.
❌ Visitor có thể thiếu quyền truy cập cần thiết vào các trường riêng tư và phương pháp của các phần tử mà họ phải làm việc với.
## 🔁 Quan hệ với các pattern khác
Bạn có thể coi **Visitor** như một phiên bản mạnh mẽ của **Command**. Các đối tượng của nó có thể thực thi các hoạt động trên các đối tượng khác nhau của các lớp khác nhau.
Bạn có thể sử dụng **Visitor** cùng với **Iterator** để duyệt qua một cấu trúc dữ liệu phức tạp và thực hiện một số thao tác trên các phần tử của nó, ngay cả khi tất cả chúng đều có các lớp khác nhau
Bạn có thể sử dụng **Visitor** để thực hiện một thao tác trên toàn bộ cây **Composite**.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/template-method)
================================================
FILE: creational-pattern/README.md
================================================
# Creational Design Patterns
Creational pattern cung cấp các cơ chế tạo đối tượng khác nhau, giúp tăng tính linh hoạt và tái sử dụng code hiện có.
## Factory Method
[](./factory-method)
Cung cấp một interface cho tạo đối tượng ở lớp cha, nhưng cho phép lớp con thay đổi kiểu đối tượng sẽ được tạo.
## Abstract Factory
[](./abstract-factory)
Giúp bạn tạo các đối tượng có liên quan với nhau trong một nhóm mà không cần chỉ định đến lớp cụ thể của chúng.
## Builder
[](./builder)
Xây dựng các đối tượng phức tạp từng bước một. Pattern này cho phép bạn tạo và biểu diễn các kiểu đối tượng khác nhau bằng code khởi tạo giống nhau.
## Prototype
[](./prototype)
Giúp bạn sao chép một đối tượng mà code của bạn sẽ không phụ thuộc vào lớp của đối tượng đó.
## Singleton
[](./singleton)
Đảm bảo ràng một lớp chỉ với một thực thể duy nhất, trong khi cung cấp điểm truy cập toàn cục cho thực thể đấy.
================================================
FILE: creational-pattern/abstract-factory/README.md
================================================
# Abstract Factory
## 📜 Mục đích
**Abstract Factory** là một design pattern thuộc nhóm creational, dùng để tạo ra các đối tượng có quan hệ gần gũi với nhau mà không cần chỉ định đến lớp cụ thể của chúng.

## 😟 Vấn đề
Giả sử bạn đang tạo một trang bán đồ nội thất. Code của bạn bao gồm các lớp sau:
1. Các sản phẩm có quan hệ với nhau như: `Sofa`, `Chair` và `CoffeTable`.
2. Các biến thể của nhóm sản phẩm đó. Ví dụ như nhóm `Sofa` + `Chair` + `CoffeTable` có các biến thể như `Modern`, `Victorian` và `ArtDeco`.

Bạn cần có cách để khi tạo một đồ nội thất đơn lẻ, nó phải phù hợp với các đồ vật khác trong nhóm của nó. Khách hàng sẽ khó chịu khi họ nhận về những đồ vật trong nhóm có biến thể khác nhau.

Bên cạnh đó, bạn không muốn thay đổi code mỗi khi thêm sản phẩm hoặc nhóm sản phẩm trong chương trình. Danh mục nội thất được cập nhật rất thường xuyên, và bạn không muốn thay đổi code mỗi khi nó diễn ra.
## 😊 Giải pháp
Việc đầu tiên cần làm theo Abstract Factory là khai báo inteface rõ ràng cho mỗi sản phẩm riêng biệt trong nhóm sản phẩm. Và tạo tất cả biến thể của sản phẩm theo sau inteface đó. Ví dụ tất cả biến thể của ghế được triển khai trong interface `Chair`, tất cả sofa được triển khai trong interface `Sofa` ,...

Bước tiếp theo là khai báo *Abstract Factory* - là interface chứa tất cả phương thức tạo cho tất cả sản phẩm trong nhóm sản phẩm (vd: `createChair`, `createSofa` và `createCoffeTable`). Các phương thức này trả về một kiểu sản phẩm **trừu tượng (abstract)** được biểu diễn bởi interface mà chúng ta trích xuất trước đó: `Chair`, `Sofa`, `CoffeTable`,...

Vậy còn các biến thể của sản phẩm? Với từng biến thể của nhóm sản phẩm, ta tạo ra một lớp factory riêng biệt dựa trên interface **Abstract Factory**. Factory là lớp trả về kiểu sản phẩm riêng biệt. Ví dụ, `ModernFurnitureFactory` có thể tạo ra các đối tượng `ModernChair`, `ModernSofa` hay `ModernCoffeTable`.
Code client làm việc với factory hay sản phẩm thông qua interface trừu tượng. Thế nên bạn có thể thay đổi kiểu factory hay biến thể của sản phẩm cho code client nhận mà không gây ra bất kỳ lỗi gì.

Giả sử client muốn một factory để tạo ghế (chair). Nó sẽ không cần quan tâm kiểu của lớp factory đó, cũng như kiểu ghế nhận về. Dù là Modern hay Victorian, nó cũng sẽ xử lý theo cùng một cách là thông qua interface trừu tượng `Chair`. Với cách tiếp cận này client chỉ cần quan tâm là ghế sẽ triển khai phương thức `sitOn` như thế nào. Bên cạnh đó, bất kỳ biến thể nào của `chair`, nó cũng sẽ phù hợp với `sofa` và `coffe-table` được tạo cùng đối tượng factory.
Nếu bạn thắc mắc: client chỉ làm việc với interface trừu tượng, vậy thì cái gì sẽ tạo ra factory ?. Thông thường ứng dụng sẽ tạo đối tượng factory cụ thể ở giai đoạn khởi tạo, nhưng trước đó ứng dụng sẽ tạo factory dựa trên kiểu cấu hình hoặc thiết lập môi trường.
## 🏢 Cấu trúc

1. **Abstract Product** là inteface cho các sản phẩm riêng biệt nhưng có quan hệ với nhau tạo nên một nhóm sản phẩm.
2. **Concrete Product** là các triển khai biến thể của abstract product, được gom nhóm theo biến thể. Mỗi abstract product (chair/sofa) sẽ được triển khai tất cả biến thể (modern, victorian).
3. **Abstract Factory** là interface có tập hợp phương thức khởi tạo cho từng abstract product.
4. **Concrete Factory** là triển khai phương thức khởi tạo của abstract factory. Mỗi concrete factory tương ứng với biến thể cụ thể của sản phẩm và chỉ tạo sản phẩm theo biến thể đó.
5. Mặc dù concrete factory tạo ra các concrete product, nhưng signature của phương thức khởi tạo trả về sẽ tương ứng với abstract product. Với cách này code client sử dụng factory sẽ không cần quan tâm tới biến thể cụ thể của sản phẩm từ factory. Nó có thể làm việc với bất kỳ biến thể nào miễn là giao tiếp với các đối tượng thông qua interface trừu tượng.
## 👨💻 Mã giả
Ví dụ này minh hoạ cách Abstract Factory có thể sử dụng để tạo các phần tử UI đa nền tảng mà không cần ghép code client với lớp UI cụ thể, đồng thời giữ cho tất cả các phần tử được tạo nhất quán với hệ điều hành đã chọn

Các phần tử UI trên các ứng dụng đa nền tảng sẽ được triển khai giống nhau, sẽ có một chút khác biệt trên các hệ điều hành khác nhau. Hơn nữa, nhiệm vụ của bạn là đảm bảo style của các phần tử UI phù hợp với hệ điều hành hiện tại. Bạn sẽ không muốn chương trình hiển thị MacOS control khi được thực thi trên Windows.
Abstract Factory sẽ khai báo tập hợp các phương thức khởi tạo mà code client có thể dùng để tạo các kiểu phần tử UI khác nhau. Concrete factory tương ứng với hệ điều hành cụ thể sẽ tạo ra các phần tử UI phù hợp với hệ điều hành đó.
Nó hoạt động như sau: khi ứng dụng bắt đầu chạy, nó sẽ kiểm tra loại hệ điều hành hiện tại. Ứng dụng sẽ dùng thông tin đó để tạo ra một đối tượng factory từ lớp tương ứng với hệ điều hành. Các phần còn lại sẽ dùng factory để tạo ra phần tử UI. Điều này ngăn việc tạo các phần tử UI sai lệch.
Với cách tiếp cận này, code client không phụ thuộc lớp cụ thể của factory hay phần tử UI, miễn là nó làm việc với các đối tượng thông qua abstract factory. Không những thế, code client còn hỗ trợ các factory khác và phần tử UI bạn thêm vào trong tương lai.
Như vậy bạn không cần chỉnh sửa code client mỗi lần thêm biến thể của phần tử UI trong ứng dụng. Bạn chỉ cần tạo một lớp factory mới tạo ra các phần tử này và sửa đổi một chút code khởi tạo để ứng dụng chọn lớp đó khi thích hợp.
```c
// Interface Abstract Factory khai bao tập hợp phương thức
// trả về kiểu abstract product khác nhau. Các sản phẩm chung
// nhóm có quan hệ với nhau về chủ đề hoặc một khái niệm cấp cao.
// Sản phẩm từ một nhóm thường có thể cộng tác với nhau. Nhóm
// sản phẩm thường có một hay nhiều biến thể, nhưng sản phẩm của
// một biến thể này sẽ không tương thích với biến thể khác.
interface GUIFactory is
method createButton():Button
method createCheckbox():Checkbox
// Concrete factory tạo ra nhóm sản phẩm thuộc về một biến thể.
// Factory đảm bảo rằng sản phẩm tạo ra luôn tương thích.
// Signature của phương thức concrete factory trả về
// abstract product, trong khi bên trong phương thức,
// concrete product được tạo ra.
class WinFactory implements GUIFactory is
method createButton():Button is
return new WinButton()
method createCheckbox():Checkbox is
return new WinCheckbox()
// Mỗi concrete factory có một biến thể sản phẩm tương ứng.
class MacFactory implements GUIFactory is
method createButton():Button is
return new MacButton()
method createCheckbox():Checkbox is
return new MacCheckbox()
// Mỗi sản phẩm riêng biệt của nhóm sản phẩm nên có một interface
// cơ sở. Tất cả biết thể của sản phẩm sẽ được triển khai từ
// interface này
interface Button is
method paint()
// Concrete product được tạo bởi concrete factory tương ứng.
class WinButton implements Button is
method paint() is
// Hiển thị button trong Windows
class MacButton implements Button is
method paint() is
// Hiển thị button trong MacOS
// Đây là interface cơ sở của một sản phẩm khác. Tất cả
// sản phẩm có thể tương tác với nhau, nhưng tương tác
// chỉ khả dụng giữa hai sản phẩm cùng một biến thể.
interface Checkbox is
method paint()
class WinCheckbox implements Checkbox is
method paint() is
// Hiển thị checkbox trong Windows
class MacCheckbox implements Checkbox is
method paint() is
// Hiển thị checkbox trong MacOS
// Code client làm việc với factory và sản phẩm chỉ thông qua
// kiểu trừu tượng: GUIFactory, Button và Checkbox. Nó giúp bạn
// chuyển bất kỳ lớp con nào của factory sang code client mà
// không làm hỏng nó.
class Application is
private field factory: GUIFactory
private field button: Button
constructor Application(factory: GUIFactory) is
this.factory = factory
method createUI() is
this.button = factory.createButton()
method paint() is
button.paint()
// Ứng dụng chọn kiểu factory tùy thuộc vào cấu hình hiện tại
// hoặc thiết lập môi trường và tạo nó trong thời gian chạy
// (thường ở giai đoạn khởi tạo).
class ApplicationConfigurator is
method main() is
config = readApplicationConfigFile()
if (config.OS == "Windows") then
factory = new WinFactory()
else if (config.OS == "Mac") then
factory = new MacFactory()
else
throw new Exception("Error! Unknown operating system.")
Application app = new Application(factory)
```
## 💡 Ứng dụng
**🐞 Sử dụng Abstract Factory khi bạn cần làm việc với nhiều biến thể của một nhóm sản phẩm, mà bạn không muốn phụ thuộc vào lớp cụ thể của sản phẩm đó - chúng có thể chưa biết trước hoặc đơn giản là bạn muốn mở rộng trong tương lai.**
⚡ Abstract Factory cung cấp cho bạn interface để tạo các đối tượng từ mỗi lớp trong nhóm sản phẩm miễn là code của bạn tạo đối tượng thông qua interface, bạn sẽ không phải lo lắng các vấn đề tạo sai biến thể của sản phẩm hay không phù hợp với sản phẩm đã tạo trong ứng dụng.
- Khi triển khai Abstract Factory cần lưu ý nến bạn có một lớp với một tập hợp phương thức Factory, nó có thể làm mờ nhiệm vụ chính của Abstract.
- Một thiết kế chương trình tốt là khi *mỗi lớp sẽ chỉ làm một nhiệm vụ*. Khi một lớp xử lý nhiều loại sản phẩm, bạn có thể trích xuất các phương thức factory của nó thành một lớp factory độc lập hoặc triển khai Abstract Factory toàn diện.
## 📋 Triển khai
1. Lập sơ đồ ma trận cho các loại sản phẩm riêng biệt so với các biến thể của chúng.
2. Khai báo interface, Abstract Product cho tất cả loại sản phẩm. Sau đó tạo ra lớp concrete product triển khai interface này.
3. Khai báo interface, Abstract Factory với tập hợp phương thức khởi tạo cho tất cả abstract product.
4. Triển khai các lớp concrete factory cho từng loại biến thể của sản phẩm
5. Tạo code khởi tạo factory đâu đó trong ứng dụng. Nó sẽ khởi tạo một trong các lớp concrete factory, dựa trên cấu hình ứng dụng hoặc thiết lập môi trường. Truyền đối tượng factory này cho tất cả lớp tạo sản phẩm.
6. Kiểm tra code và tìm tất cả các lệnh gọi trực tiếp đến constructor của sản phẩm. Thay thế chúng bằng các lệnh gọi đến phương thức tạo thích hợp trên đối tượng factory.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn có thể chắc chắn rằng các sản phẩm lấy từ một factory sẽ tương thích với nhau.
✔️ Tránh được kết hợp quá chặt chẽ giữa code client và concrete product.
✔️ *Single Responsibility Principle*. Bạn có thể di chuyển code tạo sản phẩm vào một nơi trong chương trình, giúp hỗ trợ code dễ dàng hơn.
✔️ *Open/Closed Principle*. Bạn có thể thêm các biến thể mới vào chương trình, mà không làm ảnh hưởng đến code client hiện tại.
### Nhược điểm
❌ Code có thể trở nên phức tạp khi bạn thêm vào quá nhiều interface và lớp để triển khai pattern.
## 🔁 Quan hệ với các pattern khác
Nhiều pattern bắt đầu bằng cách sử dụng **Factory Method** (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn thông qua các lớp con) và phát triển theo hướng **Abstract Factory**, **Prototype** hoặc **Builder** (linh hoạt hơn nhưng phức tạp hơn).
Các lớp **Abstract Factory** thường dựa trên một tập hợp các **Factory Method**, nhưng bạn cũng có thể sử dụng **Prototype** để cấu trúc các phương thức trên các lớp này.
**Builder** tập trung vào việc xây dựng các đối tượng phức tạp theo từng bước. **Abstract Factory** chuyên tạo các nhóm đối tượng. **Abstract Factory** trả lại sản phẩm ngay lập tức, trong khi **Builder** cho phép bạn chạy một số bước xây dựng bổ sung trước khi tìm nạp sản phẩm.
**Abstract Factory** có thể dùng như một giải pháp thay thế cho **Facade** khi bạn chỉ muốn ẩn cách các đối tượng hệ thống con được tạo ra khỏi code client.
Bạn có thể sử dụng **Abstract Factory** cùng với **Bridge**. Việc ghép nối này rất hữu ích khi một số abstract được xác định bởi **Bridge** chỉ có thể hoạt động với các triển khai cụ thể. Trong trường hợp này, **Abstract Factory** có thể đóng gói các quan hệ này và ẩn sự phức tạp khỏi code client.
Tất cả các **Abstract Factory**, **Builder** và **Prototype** đều có thể được triển khai dưới dạng các **Singleton**.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/abstract-factory)
================================================
FILE: creational-pattern/builder/README.md
================================================
# Builder
## 📜 Mục đích
**Builder** là design pattern thuộc nhóm creational, giúp bạn khởi tạo những đối tượng phức tạp theo từng bước. Pattern này cho phép bạn tạo và biểu diễn các kiểu đối tượng khác nhau bằng code khởi tạo giống nhau.

## 😟 Vấn đề
Hãy tưởng tượng một đối tượng phức tạp đòi hỏi nhiều công sức, phải tạo từng bước một với rất nhiều trường và các đối tượng lồng nhau. Các đoạn code khởi tạo như vậy sẽ nằm rất sâu trong hàm khởi tạo (constructor) khổng lồ với rất nhiều tham số. Hoặc tệ hơn là nó nằm rải rác trên các đoạn code client.

Ví dụ như làm thế nào để tạo một đối tượng `House`. Để xây dựng một ngôi nhà đơn giản, bạn cần tạo bốn bức tường, nền móng, cửa lớn, các cửa sổ phù hợp và mái nhà. Nhưng nếu sau này, bạn cần mở rộng nhà to hơn, sáng sủa hơn, với sân sau và những hệ thống tiên tiến như (hệ thống ống nước, hệ thống sưởi ấm, hệ thống dây điện)?
Giải pháp đơn giản nhất là mở rộng lớp cơ sở `House`, và tạo ra tập hợp lớp con để kết hợp tất cả các tham số. Nhưng điều này sẽ khiến bạn tạo ra một số lượng đáng kể lớp con, đồng thời với bất kỳ tham số mới nào, ví dụ như kiểu hiên nhà sẽ yêu cầu phát triển hệ phân cấp lớp nhiều hơn nữa.
Lúc này cách tiếp cận khác tránh việc tạo nhiều lớp con. Là bạn có thể tạo một hàm khởi tạo (constructor) lớn trong lớp cơ sở `House` với tất cả tham số cần thiết để điều khiển đối tượng `House`. Cách này tuy có thể giải quyết vấn đề lớp con nhưng lại rơi vào vấn đề khác.

*Nhược điểm của constructor nhiều tham số là không phải lúc nào cũng cần đến các tham số*
Trong phần lớn trường hợp, các tham số của bạn sẽ không được dùng đến, điều này làm cho *hàm khởi tạo của bạn rất tệ*. Ví dụ chỉ một phần trong nhà bạn có hồ bơi, thì những tham số liên quan đến hồ bơi sẽ vô dụng khoảng 90%.
## 😊 Giải pháp
Ý tưởng của Builder pattern là bạn sẽ trích xuất các đoạn code khởi tạo đối tượng ra khỏi lớp của nó và chuyển đến một đối tượng riêng biệt gọi là *builder*.

*Builder pattern giúp bạn khởi tạo đối tượng phức tạp theo từng bước.*
Pattern khởi tạo đối tượng theo trật tự từng bước một (vd như `buildWalls`, `buildDoor`,...).
Để tạo đối tượng, bạn thực thi một loạt các bước này trên đối tượng builder. Nhưng bạn không cần phải gọi đến tất các bước, mà chỉ cần gọi đến bước cần thiết để tạo cấu hình cụ thể của đối tượng.
Một vài bước khởi tạo yêu cầu triển khai khác nhau, khi bạn cần biểu diễn các biến thể của sản phẩm. Ví dụ: tường của một cabin sẽ được xây bằng gỗ, còn tường của một lâu đài sẽ được xây bằng đá.
Trong trường hợp đấy, ta cần tạo ra nhiều lớp builder khác nhau, để triển khai các bước xây dựng giống nhau nhưng khác về cách thức. Sau đó bạn sử dụng builder trong quá trình khởi tạo để tạo ta các kiểu đối tượng khác nhau.

Ví dụ, cần xây dựng 3 ngôi nhà, cái thứ nhất được xây từ gỗ và kính, cái thứ hai được xây từ đá và sắt còn cái thứ ba được xây từ vàng và kim cương. Như vậy với lệnh gọi các bước thực hiện như nhau, ta sẽ có một ngôi nhà thông thường, một lâu đài và một cung điện. Tuy các nhiệm vụ giống nhau nhưng các xây dựng khác nhau với từng biến thể.
Song điều này chỉ hoạt động khi code client gọi các lệnh khởi tạo tương tác với builder thông qua inteface chung.
### Director
Bạn có thể trích xuất một loạt lệnh gọi đến các bước của hàm khởi tạo, mà bạn sử dụng để xây dựng sản phẩm thành một lớp riêng biệt có tên là *director*.
Lớp director xác định thứ tự thực thi của các bước xây dựng, trong khi builder cung cấp việc triển khai cho các bước đó.

Các lớp director là không bắt buộc. Bạn có thể gọi các bước xây dựng theo thứ tự cụ thể trực tiếp từ code client. Tuy nhiên, lớp director là nơi lý tưởng để đặt các quy trình khởi tạo khác nhau mà bạn có thể sử dụng lại trong chương trình của mình.
Ngoài ra, lớp director sẽ ẩn hoàn toàn chi tiết khởi tạo của sản phẩm với code client. Code client chỉ cần liên kết với director, rồi nhận hàm khởi tạo từ director và kết quả từ builder.
## 🏢 Cấu trúc

1. **Builder** là interface khai báo các bước tạo sản phẩm chung cho tất cả loại builder.
2. **Concrete Builder** cung cấp các triển khai khác nhau cho các bước khởi tạo. Concrete Builder có thể tạo sản phẩm mà không cần theo interface chung.
3. **Product** là đối tượng kết quả. Product được tạo bởi nhiều builder khác nhau không nhất thiết phải thuộc cùng một lớp phân cấp hay interface chung.
4. **Director** lớp định nghĩa thứ tự gọi các bước khởi tạo. Vì vậy bạn có thể tạo và sử dụng cho cấu hình cụ thể của sản phẩm.
5. **Client** phải liên kết đến một trong các đối tượng builder và director. Thường chỉ được thực hiện một lần, thông qua tham số của hàm khởi tạo director. Sau đó director sẽ sử dụng đối tượng builder cho tất cả khởi tạo tiếp theo. Tuy nhiên có một giải pháp thay thế là khi client truyền đối tượng builder sang phương thức production trong director. Trong trường hợp này, bạn có thể sử dụng builder khác nhau mỗi khi cần tạo thứ gì đó với director.
## 👨💻 Mã giả
Đây là ví dụ minh hoạ cách pattern **Builder** sử dụng lại code tạo đối tượng khi xây dựng các kiểu sản phẩm khác nhau, ví dụ như xe hơi và tạo các hướng dẫn sử dụng tương ứng.

Xe hơi là một đối tượng phức tạp có thể được tạo bằng hàng trăm cách khác nhau. Thay vì một lớp `Car` với hàm khởi tạo (constructor) khổng lồ, ta sẽ trích xuất code lắp ráp xe vào một lớp `CarBuilder` riêng biệt. Lớp này sẽ có tập hợp các phương pháp cấu hình cho từng bộ phận trong xe.
Nếu code client cần lắp ráp xe theo một mô hình đặc biệt, được tinh chỉnh thì nó có thể làm việc trực tiếp với builder. Trong trường hợp khác, nó có thể uỷ thác việc lắp ráp cho lớp director, nơi biết cách sử dụng builder để tạo ra những mẫu xe thời thượng nhất.
Bạn có thể bị sốc nếu biết mọi chiếc xe đều có hướng dẫn sử dụng (hầu hết mọi người không đọc chúng :v). Hướng dẫn sử dụng là thứ mô tả mọi tính năng của chiếc xe đấy, vì vậy với các mẫu xe khác nhau sẽ có hướng dẫn sử dụng khác nhau. Đó là lý do bạn nên sử dụng cùng quy trình tạo cho chiếc xe và hướng dẫn sử dụng của nó. Dĩ nhiên, tạo hướng dẫn sử dụng không giống tạo một chiếc xe, đó là lý do ta cung cấp cho nó một lớp builder khác chuyên biệt cho việc tạo hướng dẫn sử dụng. Lớp này thực hiện các phương thức xây dựng tương tự như `CarBuilder`, nhưng thay vì chế tạo các bộ phận, nó chỉ mô tả chúng. Bằng cách truyền các builder vào cùng một đối tượng director, ta có thể tạo ra chiếc xe hay hướng dẫn sử dụng của nó.
Cuối cùng là tìm nạp đối tượng kết quả. Một chiếc xe bằng kim loại và hướng dẫn sử dụng bằng giấy dù có quan hệ những vẫn rất khác nhau. Nên ta không thể đặt phương thức nạp kết quả trong director, vì nó không kết hợp với lớp product cụ thể. Do đó ta sẽ nhận về kết quả tạo từ builder.
```c
// Sử dụng pattern Builder có ý nghĩa khi sản phẩm
// quá phức tạp và yêu cầu nhiều cấu hình mở rộng.
// Hai sản phẩm có quan hệ với nhau, dù không có
// interface chung.
class Car is
// Xe hơi có thể có GPS, hộp đen và một số ghế ngồi.
// Cái mẫu xe khác nhau(xe thể thao, SUV, xe mui trần)
// sẽ có tính năng được thiết lập khác nhau.
class Manual is
// Mỗi xe sẽ có một hướng dẫn sử dụng cho người dùng
// tương ứng với cấu hình xe đó để mô tả mọi tính năng.
// Interface builder chỉ định phương thức cụ thể để tạo
// các phần khác nhau trong đối tượng sản phẩm.
interface Builder is
method reset()
method setSeats(...)
method setEngine(...)
method setTripComputer(...)
method setGPS(...)
// Lớp concrete builder theo sau interface builder và cung cấp
// các triển khai cụ thể cho bước xây dựng. Chương trình của bạn
// sẽ có nhiều biến thể builder cho các triển khai khác nhau.
class CarBuilder implements Builder is
private field car:Car
// Một fresh builder nên bao gồm đối tượng sản phẩm trống
// để sử dụng cho các lắp ráp trong tương lai.
constructor CarBuilder() is
this.reset()
// Phương thức reset xoá đối tượng được xây dựng.
method reset() is
this.car = new Car()
// Tất cả các bước tạo làm việc với cùng một đối tượng sản phẩm.
method setSeats(...) is
// Thiết lập số ghế ngồi trong xe.
method setEngine(...) is
// Cài đặt bộ động cơ.
method setTripComputer(...) is
// Cài đặt máy tính hành trình.
method setGPS(...) is
// Cài đặt GPS.
// Concrete builder phải cung cấp phương thức của nó để
// truy xuất kết quả. Các kiểu builder khác nhau sẽ tạo
// ra sản phẩm hoàn chỉnh khác nhau mà không cần theo một
// interface chung. Do đó, phương thức này không thể khai
// báo ở interface builder (chí ít là với các ngôn ngữ lập
// trình tĩnh.)
//
// Thông thường, sau khi nhận kết quả cuối cùng từ client,
// builder sẽ sẵn sàng cho việc tạo ra một sản phẩm khác.
// Đó là lý do ta đặt lệnh gọi phương thức reset ngay phía
// sau phương thức `getProduct`. Tuy nhiên, điều này là không
// bắt buộc, bạn có thể để cho builder đợi đến lệnh gọi reset
// từ code client trước khi loại bỏ kết quả trước đó.
method getProduct():Car is
product = this.car
this.reset()
return product
// Không giống creational pattern khác, builder giúp bạn
// tạo sản phẩm không cần theo interface chung.
class CarManualBuilder implements Builder is
private field manual:Manual
constructor CarManualBuilder() is
this.reset()
method reset() is
this.manual = new Manual()
method setSeats(...) is
// Tài liệu số ghế của xe.
method setEngine(...) is
// Thêm hướng dẫn động cơ.
method setTripComputer(...) is
// Thêm hướng dẫn máy tính hành trình.
method setGPS(...) is
// Thêm hướng dẫn GPS.
method getProduct():Manual is
// Trả về hướng dẫn sử dụng và reset builder
// Director chỉ chịu trách nhiệm cho thực thi các bước xây dựng
// theo một thứ tự cụ thể. Nó hữu ích khi tạo sản phẩm theo một
// trật tự xác định hoặc một cấu hình rõ ràng.
// Nói đúng hơn, lớp director là tuỳ chọn, để client có thể gián
// tiếp điều khiển builder.
class Director is
private field builder:Builder
// Director làm việc với bất kỳ builder nào mà code client
// truyền vào nó. Với cách này, code client có thể thay đổi
// kiểu cuối cùng của sản phẩm vừa được lắp ráp.
method setBuilder(builder:Builder)
this.builder = builder
// Director có thể tạo nhiều biến thể sản phẩm
// với cùng các bước xây dựng.
method constructSportsCar(builder: Builder) is
builder.reset()
builder.setSeats(2)
builder.setEngine(new SportEngine())
builder.setTripComputer(true)
builder.setGPS(true)
method constructSUV(builder: Builder) is
// ...
// Code client tạo đối tượng builder, truyền nó vào director
// sau đó bắt đầu quá trình khởi tạo. Kết quả cuối cùng được
// truy xuất từ đối tượng builder.
class Application is
method makeCar() is
director = new Director()
CarBuilder builder = new CarBuilder()
director.constructSportsCar(builder)
Car car = builder.getProduct()
CarManualBuilder builder = new CarManualBuilder()
director.constructSportsCar(builder)
// Sản phẩm cuối cùng thường được truy xuất từ đối
// tượng builder vì director không nhận biết được
// concreate builder và sản phẩm.
Manual manual = builder.getProduct()
```
## 💡 Ứng dụng
**🐞 Sử dụng Builder để loại bỏ các "hàm khởi tạo khổng lồ"**
⚡ Giả sử bạn có một phương thức khởi tạo với 10 tham số. Gọi một con "quái vật" như vậy là rất bất tiện, nên bạn đã overload constructor để tạo ra nhiều phiên bản ít tham số hơn. Các constructor này vẫn tham chiếu đến cái chính, và truyền một số giá trị mặc định vào bất kỳ tham số nào bị bỏ qua.
```
class Pizza {
Pizza(int size) { ... }
Pizza(int size, boolean cheese) { ... }
Pizza(int size, boolean cheese, boolean pepperoni) { ... }
// ...
```
Builder cho phép bạn xây dựng đối tượng từng bước, chỉ dùng những bước bạn thực sự cần. Sau khi triển khai pattern bạn không cần nhồi nhét hàng tá tham số vào constructor.
**🐞 Sử dụng Builder khi bạn muốn code của bạn tạo ra các sản phẩm có biểu diễn khác nhau (như nhà tường và nhà gỗ)**
⚡ Builder pattern có thể áp dụng khi tạo các biểu diễn khác nhau của sản phẩm gồm các bước tương tự nhau chỉ khác về chi tiết.
**🐞 Sử dụng Builder để tạo ra những cây Composite và các đối tượng phức tạp khác**
⚡ Builder tạo sản phẩm theo từng bước một. Bạn có thể trì hoãn việc thực thi một số bước mà không làm ảnh hưởng đến sản phẩm cuối cùng. Bạn cũng có thể gọi đệ quy, điều này rất hữu ích khi bạn xây dựng đối tượng cây. Builder không để lộ sản phẩm khi đang thực hiện các bước tạo. Điều này tránh việc code client tìm nạp sản phẩm chưa hoàn chỉnh.
## 📋 Triển khai
1. Đảm bảo bạn đã xác định rõ ràng các bước khởi tạo để xây dựng tất cả sản phẩm khả dụng. Nếu không bạn không thể triển khai pattern này.
2. Khai báo các bước trong interface cơ sở Builder.
3. Tạo lớp concrete builder cho từng biểu diễn sản phẩm và triển khai các bước khởi tạo của chúng. Đừng quên rằng việc triển khai phương thức để tìm nạp kết quả cho khởi tạo. Đó là lý do phương thức này không thể đặt trong interface Builder, vì các builder khác nhau có thể tạo ra các sản phẩm không cùng interface. Do đó bạn không biết kiểu trả về của phương thức. Tuy nhiên, nếu bạn đang xử lý các sản phẩm từ một hệ thống phân cấp, thì phương pháp tìm nạp có thể được thêm vào interface cơ sở một cách an toàn.
4. Tạo lớp director. Nó bao gồm nhiều cách khác nhau để tạo sản phẩm trên cùng một đối tượng builder.
5. Code client tạo ra cả đối tượng builder và director. Trước khi bắt đầu khởi tạo, client truyền đối tượng builder vào director, thông thường client chỉ làm một lần thông qua tham số của hàm khởi tạo director. Director sử dụng builder cho tất cả khởi tạo trong tương lai. Có một cách tiếp cận khác là builder chuyển trực tiếp đến phương thức constructor của director.
6. Chỉ có thể nhận kết quả trực tiếp từ director nếu tất cả sản phẩm cùng theo một interface chung. Ngược lại thì phải nhận từ builder.
## ⚖️ Ưu nhược điểm
### Ưu điểm
✔️ Bạn có thể tạo đối tượng từng bước, bỏ qua vài bước hay chạy đệ quy.
✔️ Bạn có thể sử dụng lại code khởi tạo cho xây dựng sản phẩm có biểu diễn khác nhau.
✔️ *Single Responsibility Principle*. Bạn có thể tách code khởi tạo phức tạp khỏi logic nghiệp vụ của sản phẩm
### Nhược điểm
❌ Độ phức tạp tổng thể của code tăng lên vì pattern yêu cầu tạo nhiều lớp mới.
## 🔁 Quan hệ với các pattern khác
Nhiều pattern bắt đầu bằng cách sử dụng **Factory Method** (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn thông qua các lớp con) và phát triển theo hướng **Abstract Factory**, **Prototype** hoặc **Builder** (linh hoạt hơn nhưng phức tạp hơn).
**Builder** tập trung vào việc xây dựng các đối tượng phức tạp theo từng bước. **Abstract Factory** chuyên tạo các nhóm đối tượng. **Abstract Factory** trả lại sản phẩm ngay lập tức, trong khi **Builder** cho phép bạn chạy một số bước xây dựng bổ sung trước khi tìm nạp sản phẩm.
Bạn có thể sử dụng **Builder** khi tạo các cây **Composite** phức tạp vì bạn có thể lập trình các bước xây dựng của nó để hoạt động một cách đệ quy.
Bạn có thể kết hợp **Builder** với **Bridge**: lớp director đóng vai trò abstract, trong khi các builder khác đóng vai trò implementation.
Tất cả các **Abstract Factory**, **Builder** và **Prototype** đều có thể được triển khai dưới dạng các **Singleton**.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/builder)
================================================
FILE: creational-pattern/factory-method/README.md
================================================
# Factory Method
## 📜 Mục đích
**Factory method** là một design pattern thuộc nhóm Creational, nó cung cấp một interface để tạo đối tượng cho lớp cha (superclass), nhưng cũng cho phép các lớp con (subclass) thay đổi đối tượng sẽ được tạo.

## 😟 Vấn đề
Tưởng tượng bạn đang tạo một ứng dụng quản lý chuỗi cung ứng. Phiên bản đầu tiên của ứng dụng chỉ quản lý vận chuyển cho các xe tải, thế nên phần lớn code của bạn sẽ nằm trong lớp `Truck`.
Sau đó ứng dụng của bạn ngày càng phổ biến và bạn nhận được yêu cầu từ các công ty hàng hải để hợp nhất chuỗi cung ứng qua đường biển vào ứng dụng. Đấy là một thông tin tuyệt vời! Nhưng còn code thì sao?

*Việc thêm một lớp mới vào ứng dụng không hề đơn giản nếu phần lớn code đã được kết nối với các lớp hiện có.*
Hiện tại hầu hết code của bạn đã được ghép với lớp `Truck`. Việc thêm `Ship` vào ứng dụng sẽ yêu cầu các thay đổi với toàn bộ codebase. Và nếu bạn thêm một phương tiện vận tải nào nữa vào ứng dụng, thì bạn sẽ thay đổi code lần nữa.
Kết quả là bạn có một đống code tạp nham với rất nhiều điều kiện thay đổi của ứng dụng tùy thuộc vào loại đối tượng vận chuyển.
## 😊 Giải pháp
Factory Method gợi ý giải pháp là thay vì tạo đối tượng qua các lệnh khởi tạo trực tiếp (sử dụng toán tử `new`) thì hãy tạo bằng cách gọi phương thức *factory*. Lưu ý là đối tượng vẫn được tạo thông qua toán tử `new`, nhưng nó sẽ được gọi từ trong phương thức *factory*. Các đối tượng được trả về theo phương thức factory thường được gọi là **products**.

*Các lớp con có thể chỉnh sửa đối tượng trả về từ phương thức factory*
Thoạt nhìn, thay đổi này có vẻ vô nghĩa: chúng ta chỉ chuyển lệnh gọi *constructor* từ phần này sang phần khác của chương trình. Tuy nhiên, hãy xem xét thật kỹ lưỡng : bây giờ bạn có thể ghi đè(override) phương thức factory trong một lớp con và thay đổi `product` đang được tạo bởi phương thức này.
Song, nó vẫn có một hạn chế nhỏ: các lớp con có thể trả về các kiểu `product` khác nhau chỉ khi các `product` này có lớp cơ sở hoặc interface chung. Ngoài ra, phương thức factory trong lớp cơ sở nên có kiểu trả về được khai báo là interface này.

Ví dụ, cả hai lớp `Truck` và `Ship` đều được triển khai từ interface `Transport`, interface này khai báo một phương thức là `deliver`. Mỗi lớp sẽ triển khai phương thức này theo cách khác nhau, xe tải (truck) sẽ phân phối (deliver) hàng hoá theo đường bộ, còn tàu(ship) sẽ phân phối theo đường biển. Phương thức factory `RoadLogistics` sẽ trả về đối tượng `Truck`, còn `SeaLogistics` sẽ trả về đối tượng `Ship`.

Đoạn code sử dụng phương thức factory (thường được gọi là *code client*), không nhìn thấy sự khác biệt giữa những `product` trả về bởi các lớp con khác nhau. Client coi tất cả `product` là lớp trừu tượng **Transport**, đồng thời nó cũng biết các đối tượng transport phải có phương thức `deliver`. Nhưng chi tiết cách hoạt động thì nó không cần quan tâm.
## 🏢 Cấu trúc

1. **Product** là interface chung cho tất cả đối tượng có thể được tạo ra bởi creator hay các lớp con của nó.
2. **Concrete Product** là các triển khai khác nhau từ interface **Product**. Tạm hiểu là product con.
3. **Creator** lớp này khai báo một phương thức factory trả về đối tượng product mới. Kiểu trả về của phương thức này phải tương ứng với interface **Product**. Bạn có thể định nghĩa phương thức factory là trừu tượng để tất cả lớp con triển khai phiên bản riêng của chúng. Và phương thức factory cơ sở sẽ trả về các kiểu product mặc định.
4. **Concreta Creator** sẽ ghi đè (override) phương thức factory cơ sở để trả về một kiểu product mới. Không phải lúc nào phương thức factory cũng tạo ra một đối tượng mới, nó có thể trả về đối tượng đã tồn tại từ cache, object pool hay từ một nguồn nào đó.
## 👨💻 Mã giả
Ví dụ này minh hoạ cách phương thức Factory có thể sử dụng để tạo các phần tử UI đa nền tảng mà không cần ghép code client với lớp UI cụ thể.

Lớp dialog cơ sở dùng hiển thị các phần tử UI khác nhau cho hiển thị cửa sổ. Dưới các hệ điều hành khác nhau, các phần tử này có thể có vài khác biệt nhỏ, song nó vẫn phải đồng nhất. Button trên Window vẫn là button trên Linux.
Khi sử dụng phương thức factory, bạn không cần viết lại các logic cho dialog vớI từng hệ điều hành. Nếu ta khai báo phương thức factory để tạo button trong lớp dialog, sau này ta có thể tạo các lớp con trả về button kiểu Windows từ phương thức factory. Lớp con sau đó sẽ kế thừa phần lớn code của dialog từ lớp cơ sở, nhờ vào phương thức factory ta có thể hiển thị các button kiểu window trên màn hình.
Với pattern này khi làm việc, các lớp dialog cơ sở phải làm việc với button trừu tượng: lớp cơ sở hoặc interface cho tất cả concrete button. Theo cách này, đoạn code còn lại của dialog vẫn hoạt động, dù phải làm việc với bất kỳ kiểu button nào.
Tất nhiên, bạn có thể dùng cách này cho các phần tử UI khác. Tuy nhiên, với mỗi phương thức factory mà bạn thêm vào diago, ta sẽ dần tiến đến Abstract Factory pattern. Ta sẽ nói về pattern này ở các bài viết sau.
```c
// Lớp creator khai báo phương thức factory phải trả về
// đối tượng của lớp product. Lớp con của creator tạo
// các triển khai khác của phương thức.
// Creator có thể tạo các triển khai mặc định cho
// phương thức factory.
class Dialog is
abstract method createButton():Button
// Lưu ý, dù tên là creator, song không phải nhiệm vụ chính
// của nó là tạo product. Nó được dùng để chứa nhưng logic
// nghiệp vụ cốt lõi dựa trên đối tượng product trả về từ phương
// thức factory. Các lớp con có thể gián tiếp thay đổi logic
// bằng cách ghi đè lên phương thức factory và trả về kiểu
// product khác từ nó.
method render() is
// Gọi phương thức factory để tạo đối tượng product.
Button okButton = createButton()
// Sử dụng product.
okButton.onClick(closeDialog)
okButton.render()
// Concrete creator ghi đè lên phương thức factory để
// thay đổi kiểu product trả về.
class WindowsDialog extends Dialog is
method createButton():Button is
return new WindowsButton()
class WebDialog extends Dialog is
method createButton():Button is
return new HTMLButton()
// Interface product khai báo phương thức cho tất cả
// concrete product cần triển khai.
interface Button is
method render()
method onClick(f)
// Concrete product tạo ra các triển khai với interface product.
class WindowsButton implements Button is
method render(a, b) is
// Hiển thị button kiểu Windows
method onClick(f) is
// Đánh đấu sự kiện click trên hệ điều hành.
class HTMLButton implements Button is
method render(a, b) is
// Hiển thị button dưới dạng HTML
method onClick(f) is
// Đánh dấu sự kiện click trên trình duyệt.
class Application is
field dialog: Dialog
// Ứng dụng chon kiểu creator dựa trên cấu hình
// hiện tại hoặc môi trường thiết lập.
method initialize() is
config = readApplicationConfigFile()
if (config.OS == "Windows") then
dialog = new WindowsDialog()
else if (config.OS == "Web") then
dialog = new WebDialog()
else
throw new Exception("Error! Unknown operating system.")
// Code client làm việc với thực thể của concrete creator,
// thông qua interface cơ sở. Miễn là client vẫn làm việc với
// creator thông qua interface, bạn có thể chuyển nó vào bất
// kỳ lớp con nào của creator.
method main() is
this.initialize()
dialog.render()
```
## 💡 Ứng dụng
🐞 **Sử dụng phương thức Factory khi bạn không biết chính xác kiểu và phụ thuộc của đối tượng mà code bạn sẽ làm việc**
⚡ Phương pháp Factory phân tách code khởi tạo product với code sử dụng lại product. Do đó việc mở rộng code khởi tạo product với phần code còn lại sẽ dễ dàng hơn.
🐞 **Sử dụng phương thức Factory khi bạn cung cấp cho người dùng thư viện hay framework với cách mở rộng các thành phần trong nó**
⚡ Kế thừa có lẽ là cách dễ nhất để mở rộng các hành vi mặc định của một thư viện hay framework. Nhưng làm thế nào để framework nhận diện được đâu là lớp con của bạn, đâu là thành phần tiêu chuẩn. Giải pháp ở đây là làm giảm code khởi tạo component của framework thành một phương thức factory duy nhất và cho phép bất kỳ ai ghi đè (override) lên phương thức để thêm các phần mở rộng cho component đó.
Ví dụ, bạn đang tạo một ứng dụng dựa trên một framework UI mã nguồn mở. Bây giờ bạn muốn có một button dạng tròn cho ứng dụng, nhưng framework chỉ hỗ trợ button vuông. Thế nên bạn cần mở rộng lớp tiêu chuẩn `Button` thành lớp con `RoundButton`. Bây giờ bạn cần nói cho lớp chính `UIFramework` rằng sử dụng lớp con button mới thay vì mặc định. Để làm được điều đó, bạn tạo lớp con `UIWithRoundButtons` từ lớp cơ sở của framework và ghi đè lên phương thức `createButton`. Trong khi phương thức ở lớp cơ sở trả về đối tượng `Button` thì lớp con của bạn sẽ trả về đối tượng `RoundButton`. Bây giờ bạn sẽ sử dụng `UIWithRoundButtons` thay vì `UIFramework`.
🐞 **Sử dụng phương thức Factory khi bạn muốn tiết kiệm tài nguyên hệ thống bằng cách sử dụng lại đối tượng hiện có thay vì tạo mới chúng mỗi lần**
⚡ Bạn thường gặp phải yêu cầu này khi làm việc với các đối tượng lớn, sử dụng nhiều tài nguyên như kết nối cơ sở dữ liệu, hệ thống file, tài nguyên mạng,..
Bây giờ hãy nghĩ về những việc phải làm với đối tượng hiện có:
1. Bạn cần nơi để lưu trữ tất cả các đối tượng đã tạo.
2. Khi ai đó yêu cầu một đối tượng, chương trình sẽ thực hiện tìm kiếm đối tượng đó trong pool.
3. ...và trả về cho code client.
4. Nếu không có đối tượng, chương trình sẽ tạo ra một đối tượng mới (và thêm nó vào pool).
Có khá nhiều code, và ta phải đặt chúng vào một nơi duy nhất để không rối chương trình do các đoạn code có thể bị trùng. Có lẽ nơi rõ ràng và thuận tiện nhất mà code này có thể được đặt là tại hàm khởi tạo của lớp có các đối tượng mà ta đang cố gắng sử dụng lại. Tuy nhiên, một hàm khởi tạo luôn phải trả về các đối tượng mới theo định nghĩa. Nó không thể trả lại các phiên bản hiện có.
Do đó, bạn cần phải có một phương thức có khả năng tạo các đối tượng mới cũng như sử dụng lại các đối tượng hiện có. Và đó chính là phương thức Factory.
## 📋 Triển khai
1. Tạo tất cả product theo cùng một interface. Interface này nên khai báo phương thức có ý nghĩa với tất cả product.
2. Thêm phương thức factory trống vào lớp creator. Kiểu trả về của phương thức nên tương ứng với interface product chung.
3. Trong code creator tìm tất cả tham chiếu đến hàm khởi tạo product. Từng cái một, thay thế nó với lệnh gọi phương thức factory, trong khi trích xuất code tạo product vào phương thức factory. Bạn cần thêm tham số mẫu vào phương thức factory để điều khiển kiểu trả về của product.
4. Bây giờ, tạo tập hợp lớp con của creator cho từng kiểu product trong phương thức factory. Ghi đè lên phương thức factory ở lớp con và trích xuất các bit phù hợp từ hàm khởi tạo với phương thức cơ sở.
5. Nếu có quá nhiều kiểu product và nó không phù hợp tạo lớp con cho chúng, ta có thể tái sử dụng tham số điều khiển từ lớp cở sở ở lớp con. Ví dụ, bạn có một hệ thống phân cấp các lớp như sau: lớp cơ sở `Mail` với hai lớp con: `AirMail` và `GroundMail`; lớp `Transport` có `Plane`, `Truck` và `Train`. Trong khi lớp `AirMail` chỉ dùng đối tượng `Plane`, thì `GroundMail` làm việc với cả hai đối tượng `Truck` và `Train`. Bạn có thể tạo lớp con (tạm gọi `TrainMail`) để xử lý cả hai trường hợp, nhưng cũng có lựa chọn khác. Code client có thể gửi tham số vào phương thức factory của `GroundMail` để điều khiển kiểu product mà nó muốn nhận.
6. Sau cùng, nếu phương thức factory ở lớp cơ sở trống, bạn có thể chuyển nó thành trừu tượng(abstract). Nếu còn sót lại gì đó thì ta sẽ thiết lập đó là hành vi mặc định của phương thức.
## ⚖️ Ưu nhược điểm
**Ưu điểm**
✔️ Tránh được kết hợp quá chặt chẽ giữa creator và concrete product.
✔️ *Single Responsibility Principle*. Bạn có thể di chuyển code tạo product vào một nơi trong chương trình, giúp code hỗ trợ dễ dàng hơn.
✔️ *Open/Closed Principle*. Bạn có thể thêm các kiểu product mới vào chương trình, mà không làm ảnh hưởng đến code client hiện tại.
**Nhược điểm**
❌ Code có thể trở nên phức tạp khi bạn thêm vào quá nhiều lớp con để triển khai pattern. Trường hợp tốt nhất là khi bạn triển khai pattern bằng cách sử dụng hệ thống phân cấp của lớp creator.
## 🔁 Quan hệ với các pattern khác
Nhiều pattern bắt đầu bằng cách sử dụng **Factory Method** (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn thông qua các lớp con) và phát triển theo hướng **Abstract Factory**, **Prototype** hoặc **Builder** (linh hoạt hơn nhưng phức tạp hơn).
Các lớp **Abstract Factory** thường dựa trên một tập hợp các **Factory Method**, nhưng bạn cũng có thể sử dụng **Prototype** để cấu trúc các phương thức trên các lớp này.
Bạn có thể sử dụng **Factory Method** cùng với **Iterator** để cho phép các lớp con của collection trả về các kiểu vòng lặp khác nhau tương thích với các collection.
**Prototype** không dựa trên sự kế thừa, vì vậy nó không có nhược điểm. Mặt khác, **Prototype** yêu cầu khởi tạo nhân bản đối tượng phức tạp. **Factory Method** dựa trên kế thừa nhưng không yêu cầu bước khởi tạo.
**Factory Method** là một chuyên môn hóa của **Template Method**. Đồng thời, **Factory Method** có thể đóng vai trò là một bước trong một **Template Method** lớn.
# Nguồn
[**refactoring**](https://refactoring.guru/design-patterns/factory-method)
================================================
FILE: creational-pattern/prototype/README.md
================================================
# Prototype
## 📜 Mục đích
**Prototype** là một design pattern thuộc nhóm creational, giúp bạn sao chép một đối tượng mà code của bạn sẽ không phụ thuộc vào lớp của đối tượng đó.

## 😟 Vấn đề
Giả sử bạn đang có một đối tượng và bạn muốn tạo ra bản sao của nó. Vậy làm thế nào ? Đầu tiên bạn sẽ tạo ra một đối tượng mới có cùng lớp, sau đó bạn sẽ lấy giá trị từ tất cả các trường của đối tượng gốc và gán nó sang cho đối tượng mới.
Hay lắm ! Nhưng nó có vấn đề. Không phải tất cả đối tượng đều có thể sao chép theo cách này vì có thể một vài trường của nó là riêng tư (private) và không thể truy cập từ bên ngoài đối tượng.

*Copy đối tượng từ bên ngoài không phải lúc nào cũng tốt*
Có nhiều hơn một vấn đề với cách tiếp cận này, là khi bạn biết lớp của đối tượng mà bạn tạo bản sao, code của bạn sẽ trở nên phụ thuộc vào lớp đó. Nếu điều này chưa làm bạn lo lắng thì còn một vấn đề nữa. Là thỉnh thoảng bạn chỉ biết interface của đối tượng, chứ không biết đến lớp cụ thể, khi đó tham số trong các phương thức của bạn sẽ chấp nhận bất kỳ đối tượng nào theo interface đấy.
## 😊 Giải pháp
Pattern Prototype uỷ thác quá trình sao chép cho các đối tượng thực đang được sao chép. Pattern này khai báo một interface chung hỗ trợ sao chép cho tất cả đối tượng. Interface này giúp bạn sao chép đối tượng mà không cần ghép code của bạn với lớp của đối tượng. Thông thường, interface như vậy chỉ bao gồm một phương thức `clone`.
Triển khai phương thức `clone` là như nhau với mọi lớp. Phương thức tạo một đối tượng của lớp hiện tại và chuyển tất cả trường giá trị của đối tượng cũ sang đối tượng mới. Thậm chí có thể sao chép cả trường riêng tư vì phần lớn ngôn ngữ lập trình cho phép đối tượng truy cập trường riêng tư của đối tượng khác nếu chúng cùng thuộc một lớp.
Đối tượng hỗ trợ sao chép gọi là *prototype*. Khi đối tượng của bạn có hàng chục trường và hàng trăm cấu hình khả khi, nhân bản chúng có thể xem như một giải pháp thay thế cho tạo lớp con.

*Các prototype tạo sẵn có thể thay thế cho phân lớp.*
Cách mà nó hoạt động: bạn tạo một tập hợp các đối tượng, được cấu hình theo nhiều cách khác nhau. Khi bạn cần một đối tượng giống như đối tượng bạn đã cấu hình, bạn chỉ cần sao chép một prototype thay vì xây dựng một đối tượng mới từ đầu.
## 🚗 Thế Giới Thực
Trong cuộc sống thực, các prototype được sử dụng để thực hiện các thử nghiệm khác nhau trước khi bắt đầu sản xuất hàng loạt một sản phẩm. Tuy nhiên, trong trường hợp này các prototype không tham gia vào bất kỳ quá trình sản xuất thực nào, nó chỉ đóng vai trò thụ động. Vì các prototype trong công nghiệp không thực sự tự sao chép.

Một ví dụ thực nữa của pattern này quá trình nguyên phân trong sinh học. Sau khi nguyên phân, một cặp tế bào giống hệt nhau được hình thành. Tế bào gốc lúc này hoạt động như một prototype và đóng vai trò chủ động.
## 🏢 Cấu trúc
### Triển khai cơ bản

1. **Prototype** là interface khai báo phương thức sao chép. Trong đa số trường hợp, nó chỉ có một phương thức `clone`.
2. **Concrete Prototype** lớp triển khai phương thức sao chép. Ngoài việc sao chép dữ liệu của đối tượng ban đầu sang bản sao, phương pháp này cũng có thể xử lý một số trường hợp của quá trình sao chép liên quan đến việc sao chép các đối tượng được liên kết, gỡ rối các phụ thuộc đệ quy, ...
3. **Client** có thể tạo một bản sao của bất kỳ đối tượng nào theo interface prototype.
### Triển khai prototype registry

1. **Prototype Registry** cung cấp cách để truy cập dễ dàng các prototype được sử dụng thường xuyên. Nó lưu trữ một tập hợp đối tượng đã tạo sẵn cho việc sao chép. Prototype registry đơn giản nhất là là một hashmap `name → prototype`. Tuy nhiên, nếu bạn cần các tiêu chí tìm kiếm tốt hơn, bạn có thể tự xây dựng một phiên bản registry mạnh mẽ hơn.
## 👨💻 Mã giả
Trong ví dụ này, Prototype Pattern cho phép bạn tạo các bản sao chính xác của các đối tượng hình học mà không cần ghép code với các lớp của chúng.

Tất cả các lớp hình dạng theo sau một interface, cung cấp phương thức sao chép. Lớp con có thể gọi phương thức sao chép của lớp cha trước khi sao chép các trường giá trị của chính nó vào đối tượng kết quả.
```c
// Prototype cơ sở.
abstract class Shape is
field X: int
field Y: int
field color: string
// Hàm khởi tạo thông thường.
constructor Shape() is
// ...
// Hàm khởi tạo prototype. Đối tượng rỗng được tạo
// với giá trị từ đối tượng đã tồn tại.
constructor Shape(source: Shape) is
this()
this.X = source.X
this.Y = source.Y
this.color = source.color
// Phương thức clone trả về một trong những lớp con Shape.
abstract method clone():Shape
// Concrete prototype. Phương thức sao chép tạo đối t
gitextract_jadc42aa/
├── README.md
├── _config.yml
├── behavioral-pattern/
│ ├── README.md
│ ├── chain-of-responsibility/
│ │ └── README.md
│ ├── command/
│ │ └── README.md
│ ├── iterator/
│ │ └── README.md
│ ├── mediator/
│ │ └── README.md
│ ├── memento/
│ │ └── README.md
│ ├── observer/
│ │ └── README.md
│ ├── state/
│ │ └── README.md
│ ├── strategy/
│ │ └── README.md
│ ├── template-method/
│ │ └── README.md
│ └── visitor/
│ └── README.md
├── creational-pattern/
│ ├── README.md
│ ├── abstract-factory/
│ │ └── README.md
│ ├── builder/
│ │ └── README.md
│ ├── factory-method/
│ │ └── README.md
│ ├── prototype/
│ │ └── README.md
│ └── singleton/
│ └── README.md
└── structural-pattern/
├── README.md
├── adapter/
│ └── README.md
├── bridge/
│ └── README.md
├── composite/
│ └── README.md
├── decorator/
│ └── README.md
├── facade/
│ └── README.md
├── flyweight/
│ └── README.md
└── proxy/
└── README.md
Condensed preview — 27 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (377K chars).
[
{
"path": "README.md",
"chars": 7074,
"preview": "# DESIGN PATTERN LÀ GÌ ?\n\n\n\nDesign Pattern là một giải pháp tổng thể cho "
},
{
"path": "_config.yml",
"chars": 27,
"preview": "theme: jekyll-theme-tactile"
},
{
"path": "behavioral-pattern/README.md",
"chars": 2312,
"preview": "# Behavioral Design Pattern\n\nBehavioral Pattern quan tâm đến việc giao tiếp hiệu quả và phân công nhiệm vụ giữa các đối "
},
{
"path": "behavioral-pattern/chain-of-responsibility/README.md",
"chars": 15365,
"preview": "# Chain of Responsibility\n\n## 📜 Mục đích\n\n**Chain of Responsibility** là một design pattern trong nhóm behavioral cho ph"
},
{
"path": "behavioral-pattern/command/README.md",
"chars": 18354,
"preview": "# Command\n\n## 📜 Mục đích\n\n**Command** là một design pattern thuộc nhóm behavioral, nó biến một yêu cầu thành một đối tượ"
},
{
"path": "behavioral-pattern/iterator/README.md",
"chars": 13619,
"preview": "# Iterator\n\n## 📜 Mục đích\n\n**Iterator** là một design pattern thuộc nhóm behavioral giúp bạn duyệt phần tử của một tập h"
},
{
"path": "behavioral-pattern/mediator/README.md",
"chars": 14013,
"preview": "# Mediator\n\n## 📜 Mục đích\n\nMediator là một desgin pattern thuộc nhóm behavioral giúp bạn giảm các phụ thuộc hỗn tạp giữa"
},
{
"path": "behavioral-pattern/memento/README.md",
"chars": 15325,
"preview": "# Memento\n\n## 📜 Mục đích\n\nMemento là một desgin pattern thuộc nhóm behavioral giúp bạn lưu và phục hồi trạng thái trước "
},
{
"path": "behavioral-pattern/observer/README.md",
"chars": 13330,
"preview": "# Observer\n\n## 📜 Mục đích\n\nObserver là một design pattern thuộc nhóm behavioral giúp bạn định nghĩa một cơ chế đăng ký đ"
},
{
"path": "behavioral-pattern/state/README.md",
"chars": 13556,
"preview": "# State\n\n## 📜 Mục đích\n\n**State** là một design pattern thuộc nhóm behavoiral giúp chỉnh sửa hành vi của một đối tượng k"
},
{
"path": "behavioral-pattern/strategy/README.md",
"chars": 12231,
"preview": "# Strategy\n\n## 📜 Mục đích\n\n**Strategy** là một design pattern thuộc nhóm behavioral giúp bạn xác định một nhóm thuật toá"
},
{
"path": "behavioral-pattern/template-method/README.md",
"chars": 10388,
"preview": "# Template Method\n\n## 📜 Mục đích\n\n**Template Method** là một design pattern thuộc nhóm behavioral giúp định nghĩa bộ khu"
},
{
"path": "behavioral-pattern/visitor/README.md",
"chars": 13828,
"preview": "# Visitor\n\n## 📜 Mục đích\n\n**Visitor** là một design pattern thuộc nhóm behavioral giúp bạn tách các thuật toán khỏi đối "
},
{
"path": "creational-pattern/README.md",
"chars": 1155,
"preview": "# Creational Design Patterns\n\nCreational pattern cung cấp các cơ chế tạo đối tượng khác nhau, giúp tăng tính linh hoạt v"
},
{
"path": "creational-pattern/abstract-factory/README.md",
"chars": 12430,
"preview": "# Abstract Factory\n\n## 📜 Mục đích\n\n**Abstract Factory** là một design pattern thuộc nhóm creational, dùng để tạo ra các "
},
{
"path": "creational-pattern/builder/README.md",
"chars": 15845,
"preview": "# Builder\n\n## 📜 Mục đích\n\n**Builder** là design pattern thuộc nhóm creational, giúp bạn khởi tạo những đối tượng phức tạ"
},
{
"path": "creational-pattern/factory-method/README.md",
"chars": 13653,
"preview": "# Factory Method\n\n## 📜 Mục đích\n\n**Factory method** là một design pattern thuộc nhóm Creational, nó cung cấp một interfa"
},
{
"path": "creational-pattern/prototype/README.md",
"chars": 11767,
"preview": "# Prototype\n\n## 📜 Mục đích\n\n**Prototype** là một design pattern thuộc nhóm creational, giúp bạn sao chép một đối tượng m"
},
{
"path": "creational-pattern/singleton/README.md",
"chars": 8062,
"preview": "# Singleton\n\n## 📜 Mục đích\n\n**Singleton** là một design pattern thuộc nhóm creational giúp bạn tạo ra một lớp chỉ với mộ"
},
{
"path": "structural-pattern/README.md",
"chars": 1610,
"preview": "# Structural Design Patterns\n\nStructural Pattern giải thích cách tập hợp các đối tượng và lớp thành các cấu trúc lớn hơn"
},
{
"path": "structural-pattern/adapter/README.md",
"chars": 10446,
"preview": "# Adapter\n\n## 📜 Mục đích\n\n**Adapter** là một design pattern thuộc nhóm structural cho phép các đối tượng có interface kh"
},
{
"path": "structural-pattern/bridge/README.md",
"chars": 12352,
"preview": "# Bridge\n\n## 📜 Mục đích\n\n**Bridge** là design pattern thuộc nhóm structural giúp bạn tách một lớp khổng lồ hoặc một tập "
},
{
"path": "structural-pattern/composite/README.md",
"chars": 10734,
"preview": "# Composite\n\n## 📜 Mục đích\n\n**Composite** là một design pattern thuộc nhóm structural cho phép bạn sắp xếp các đối tượng"
},
{
"path": "structural-pattern/decorator/README.md",
"chars": 15434,
"preview": "# Decorator\n\n## 📜 Mục đích\n\n**Decorator** là một design pattern thuộc nhóm structural giúp bạn thêm một hành vi mới vào "
},
{
"path": "structural-pattern/facade/README.md",
"chars": 8516,
"preview": "# Facade\n\n## 📜 Mục đích\n\n**Facade** là design pattern thuộc nhóm structural cung cấp interface đơn giản cho thư viện, fr"
},
{
"path": "structural-pattern/flyweight/README.md",
"chars": 12139,
"preview": "# Flyweight\n\n## 📜 Mục đích\n\n**Flyweight** là design pattern thuộc nhóm structural giúp bạn chỉnh các đối tượng phù hợp v"
},
{
"path": "structural-pattern/proxy/README.md",
"chars": 11272,
"preview": "# Proxy\n\n## 📜 Mục đích\n\n**Proxy** là một design pattern thuộc nhóm structural cho phép bạn cung cấp một vật thay thế hoặ"
}
]
About this extraction
This page contains the full source code of the Ren0503/design-pattern GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 27 files (287.9 KB), approximately 75.6k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.