---
# System prepended metadata

title: Bài tập Lập trình Hướng đối tượng

---

# Bài tập Lập trình Hướng đối tượng
## Cơ bản về lập trình và lập trình hướng đối tượng
### Buổi 1 (18/02/2024): Các khái niệm cơ bản trong lập trình, giới thiệu về OOP trong C++
#### Bài 1: Quản lý học sinh
:::info
Thực hiện các yêu cầu sau trong một chương trình dạng **Console Application** bằng **C++**.
:::

Định nghĩa một cấu trúc dữ liệu đơn giản (`struct`) để lưu trữ thông tin về học sinh, bao gồm:
- Họ và tên
- Lớp
- Giới tính
- Số thứ tự học sinh trong lớp
- Điểm trung bình môn Toán
- Điểm trung bình môn Văn
- Điểm trung bình môn Anh
- Điểm trung bình môn Lý
- Điểm trung bình môn Hoá

:::warning
:bulb: Bạn có thể sử dụng lớp `string` (trong thư viện `<string>`) để lưu chuỗi.
:::

Viết một hàm để nhập thông tin của một học sinh từ bàn phím và trả về một đối tượng học sinh.
```cpp=
HocSinh tao_hoc_sinh()
```

Viết một hàm để tính điểm trung bình của một học sinh (trung bình cộng của 5 môn).
```cpp=
double tinh_diem_trung_binh(HocSinh hs)
```

Viết một hàm để hiển thị thông tin của một học sinh ra màn hình với mẫu: `Hoc sinh Nguyen Van A (STT 20 - Lop 10A1) co DTB cac mon la 8.2`
```cpp=
void xem_thong_tin_hoc_sinh(HocSinh hs)
```


Viết một hàm để đánh giá xếp loại của một học sinh dựa trên điểm trung bình:
- Nếu điểm trung bình >= 9, xếp loại là `Xuat sac`.
- Nếu điểm trung bình >= 8 và < 9, xếp loại là `Gioi`.
- Nếu điểm trung bình >= 7 và < 8, xếp loại là `Kha`.
- Nếu điểm trung bình >= 5 và < 7, xếp loại là `Trung binh`.
- Nếu điểm trung bình < 5, xếp loại là `Yeu`.


Trong hàm `main()`:
- Khai báo một **mảng** có thể chứa thông tin của nhiều học sinh trong lớp. Lưu ý: số lượng học sinh trong lớp từ 1 đến 40.
- Sử dụng một vòng lặp để cho phép người dùng nhập thông tin của nhiều học sinh và lưu vào mảng. Lưu ý: điểm nhập vào phải được kiểm soát trong đoạn từ 0 đến 10.
- Hiển thị thông tin của tất cả các học sinh đã nhập.
- Hiển thị xếp loại của từng học sinh.

:::warning
:bulb: Để khai báo mảng, học viên vui lòng tìm hiểu thêm về mảng trong C++:
```cpp=
int main() {
    const int SL_HS_TOI_DA = 40;
    HocSinh ds[SL_HS_TOI_DA];
    int n; // so luong hoc sinh
    
    do {
    cout << "Nhap so luong hoc sinh trong lop = ";
    cin >> n;
    } while (n < 1 || n > SL_HS_TOI_DA);
    
    // Nhap mang
    for (int i = 0; i < n; i++) {
        ds[0] = tao_hoc_sinh();
    }
    
    // ...
}
```
:::

- Viết thêm một số hàm thống kê:
    - Số lượng học sinh được loại xuất sắc, giỏi, khá,...
    - Trung bình cộng điểm trung bình của các học sinh trong lớp.
    - Ta sẽ chọn ra 2 học sinh có điểm trung bình cao nhất để nhận thưởng, cho biết thông tin của 2 học sinh đó.

Dưới đây là dữ liệu mẫu:

| STT | Họ và tên    | Lớp  | Giới tính | Điểm Toán | Điểm Văn | Điểm Anh | Điểm Lý | Điểm Hoá |
| --------- | ------------ | ---- | --------- | --------- | -------- | -------- | ------- | -------- |
| 1         | Nguyễn Văn A | 10A1 | Nam       | 4.5       | 7.5      | 6.0      | 5.0     | 2.5      |
| 2         | Trần Thị B   | 10A1 | Nữ        | 7.0       | 8.0      | 9.0      | 6.5     | 8.5      |
| 3         | Phạm Văn C   | 10A1 | Nam       | 9.0       | 9.5      | 9.0      | 10.0     | 8.5      |
| 4         | Lê Thị D     | 10A1 | Nữ        | 6.5       | 7.0      | 8.0      | 7.5     | 6.0      |
| 5         | Hoàng Văn E  | 10A1 | Nam       | 1.0       | 2.5      | 3.5      | 4.0     | 3.0      |
| 6         | Mai Thị F    | 10A1 | Nữ        | 9.5       | 9.0      | 9.0      | 9.5     | 10.0      |
| 7         | Đỗ Văn G     | 10A1 | Nam       | 8.5       | 9.0      | 6.0      | 7.5     | 8.0      |
| 8         | Nguyễn Thị H | 10A1 | Nữ        | 6.0       | 6.5      | 8.0      | 6.0     | 5.5      |
| 9         | Trần Văn I   | 10A1 | Nam       | 8.0       | 7.5      | 9.0      | 6.5     | 6.5      |
| 10        | Phạm Thị K   | 10A1 | Nữ        | 8.0       | 8.0      | 7.5      | 8.5     | 9.0      |

#### Bài 2:
:::info
Thực hiện các yêu cầu sau trong một chương trình dạng **Console Application** bằng **C++**.

Hãy cài đặt các lớp đối tượng theo như sơ đồ sau:
:::

![Untitled](https://hackmd.io/_uploads/ry_OBKynp.jpg)

:::warning
:bulb: Yêu cầu cài đặt: Các thuộc tính phải là `private` và có getters, setters cho từng thuộc tính.
:::
---

### Buổi 2 (25/02/2024): Lớp đối tượng, thuộc tính, phương thức

Trong bài tập này, bạn sẽ tự tạo lại một lớp `vector` của riêng bạn (gọi là `MyVector`), bắt chước một số đặc tính có sẵn của lớp `vector` có sẵn trong STL (đương nhiên không cần làm lại toàn bộ).

**Yêu cầu chung**:
- Bạn không cần cài đặt theo kiểu generic, mặc định mảng trong `MyVector` sẽ chứa các số nguyên `int`.
- Sử dụng cơ chế cấp phát động và tự động mở rộng mảng nếu thêm vào một phần tử mới làm vượt quá sức chứa hiện tại của mảng. Giả định rằng sức chứa sẽ được mở rộng gấp đôi ở mỗi lần.
- Các thuộc tính sử dụng trong lớp bắt buộc phải là `private`
- Với constructors:
    - `MyVector()`: Sức chứa ban đầu là 0
    - `MyVector(int cap)`: Sức chứa ban đầu là `cap` và các phần tử đều là 0.
    - `MyVector(int cap, int x)`: Khởi tạo mảng với sức chứa ban đầu là `cap` và các phần tử đều gán là `x`
    - `MyVector(int* a, int N)`: Khởi tạo mảng với sức chứa ban đầu là `N` và các phần tử sao chép lại các phần tử từ mảng `a`.
    - `MyVector(const MyVector& m)`: Sao chép vector `m` để tạo ra vector mới (sức chứa đúng bằng `m.size()`)
- Các phương thức cần cài đặt:
    - `int size()`: Lấy kích thước hiện tại
    - `int cap()`: Lấy sức chứa hiện tại
    - `int get(int id)`: Lấy phần tử tại vị trí `id`
    - `int set(int id, int x)`: Gán phần tử tại vị trí `id` giá trị `x`
    - `void add(int x)`: Thêm phần tử `x` vào cuối mảng
    - `void remove(int id)`: Xoá phần tử ở vị trí `id`
    - `void delete(int x, int c = 1)`: Xoá `c` phần tử `x` trong mảng (từ trái sang), với `c` mặc định là 1 (chỉ xoá 1 phần tử)
    - `void insert(int id, int x)`: Chèn phần tử `x` vào vị trí `id`
    - `int find(int x, int from = 0)`: Tìm phần tử `x` trong mảng, nếu có trả về vị trí, nếu không tìm được trả về -1 (tham số `from` chỉ vị trí bắt đầu tìm kiếm, mặc định là tìm từ đầu mảng `from = 0`)
    - `void resize(int N)`: Thay đổi kích thước hiện tại (nới rộng hoặc thu hẹp), nếu thu hẹp thì các phần tử dư ra bị loại bỏ, nếu nới rộng thì các phần tử mới sẽ được khởi gán bằng 0.
    - `MyVector sub(int i, int l)`: Tạo ra một vector mới sao chép một đoạn con trong vector cũ từ chỉ số `i` đến chỉ số `i+l-1` (tức là mảng con này có đúng `l` phần tử)
    - Ngoài ra, bạn có thể tìm hiểu thêm lớp `vector` của C++ và cài thêm một số phương thức nữa nếu muốn.


---

### Buổi 3 (03/03/2024): C# OOP và các lớp đối tượng có sẵn
Trang trại gia súc của Mc Donald có nuôi một số các con vật sau: Vịt, Cừu, Bò.

Các con vật này đều có thể phát ra tiếng kêu đặc trưng. Tất cả các con vật được nuôi đều là giống cái.

**Bạn được chỉ định thực hiện các yêu cầu sau**:
1. Tự phát sinh ra n con vật thuộc 3 kiểu vịt, cừu và bò.
- Thủ tục phát sinh như sau:
    + Phát sinh ngẫu nhiên số n
    + Lặp tự 1 đến n, mỗi lần lại ngẫu nhiên sinh ra một con vật thuộc 1 trong 3 kiểu vịt, cừu, bò.
2. Thống kê đã sinh ra bao nhiêu con mỗi loại.
3. Một hôm Mc Donald đi vắng, tất cả gia súc trong nông trại đều đói. Hãy cho biết những tiếng kêu nghe được trong nông trại.
4. Chỉ có bò mới có thể cho sữa. Hãy duyệt qua mảng một lần để vắt sữa (nếu đó là con bò) và thống kê số lượng sữa thu được, biết số lít sữa bò cho là ngẫu nhiên trong khoảng từ 0 đến 20 lít.
5. Vì tất cả đều là con cái nên lần lượt duyệt qua toàn bộ mảng và gọi hàm sinh để thêm vào mảng các con vật mới (giả sử khi hàm sinh được gọi thì ta có luôn một con non). Biết số con sinh được là ngẫu nhiên trong khoảng từ 0-4.

:::info
:bulb: Một số lưu ý:
- Bài tập này được cài trên ngôn ngữ C#.
- Đối với các yêu cầu liên quan đến con số ngẫu nhiên, bạn hãy tham khảo các phương thức trong lớp `Random` được cài sẵn trong C#.
- Đối với yêu cầu 3, 4 và 5, bạn phải duyệt qua mảng các gia súc, lần lượt gọi các hàm của từng con vật thông qua đa hình. Việc lưu trữ các con vật trong một mảng bạn có thể tham khảo các lớp [Collections](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/collections) được cài sẵn, ví dụ `List`.
:::

---

## Mở đầu về lập trình giao diện

### Buổi 4 (10/03/2024): Làm việc với File, Ứng dụng WPF và các thành phần cơ bản của WPF
:::warning
Do mở rộng quy mô, trang trại gia súc của Mc Donald đang cần một phần mềm để quản lý thông tin của các gia súc đang được chăn nuôi.
:::

Trong bài tập tuần này, bạn được yêu cầu thiết kế ra một phần mềm giao diện đơn giản để:
- Nhập thông tin cho đám gia sức
- Lưu lại thông tin của đám gia súc
- Tải lại thông tin cũ đã lưu trước đó

Dưới đây là giao diện bạn cần phải thiết kế được sau bài tập này (bạn có thể thiết kế khác đi, tuy nhiên vẫn phải đảm bảo được các chức năng nêu trên)
            
![image](https://hackmd.io/_uploads/BymZMs3Ta.png)

**Một số ràng buộc về tính năng:**
- Thông tin con vật nhập vào phải đầy đủ cả tên, giống, loại con vật.
- Nếu lưu danh sách hiện tại mà đã có sẵn file dữ liệu cũ trước đó, cần hiện ra một `MessageBox` để cảnh báo người dùng xem có muốn ghi đè không.
- Khi tải danh sách cũ lên, danh sách hiện tại sẽ được làm sạch. Do đó cũng cần phải xác nhận xem người dùng có muốn xoá danh sách hiện tại không.

:::info
:bulb: Một số lưu ý:
- Bài tập này được cài trên ngôn ngữ C# với loại ứng dụng giao diện WPF trên .NET Framework 4.7 trở lên.
- `MessageBox` ngoài việc chỉ hiển thị ra thông điệp đơn giản còn có thể hiển thị kèm các nút bấm như `OK`, `Cancel`, biểu tượng cảnh báo,... bạn có thể tìm hiểu thêm các overloading trong phương thức `Show` của lớp này.
- Giao diện 2 cột như trên được cài đặt nhờ kết hợp `Grid` chứa `StackPanel` (bên trái) và `ListBox` (bên phải).
    ```html=
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="2*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel>

        </StackPanel>
        <ListBox Grid.Column="1" Name="lbVatNuoi">

        </ListBox>
    </Grid>

    ```
- Tạo ra danh sách lựa chọn giống và lựa chọn loài thông qua `ComboBox`. Ở ví dụ dưới đây, ta có thể lấy chỉ số của mục đang được chọn nhờ thuộc tính `cmbKind.SelectedIndex`
    ```html=
    <ComboBox Name="cmbKind" >
        <ComboBoxItem>Cừu</ComboBoxItem>
        <ComboBoxItem>Bò</ComboBoxItem>
        <ComboBoxItem>Vịt</ComboBoxItem>
    </ComboBox>
    ```
- Để hiển thị danh sách, ta sẽ thêm các đối tượng con vật vào thuộc tính `Items` của `ListBox` (thuộc tính này sử dụng như một `List` thông thường).
    ```csharp=
    Cow newCow = new Cow() { Name = "Daisy 1", Gender = Genders.Male };
    lbVatNuoi.Items.Add(newCow);
    ```
:::



---
## Các mẫu thiết kế hướng đối tượng và ứng dụng

### Buổi 5 (17/03/2024): Các mẫu thiết kế nhóm tạo lập

:::danger
Tạm gác việc xây dựng giao diện cho ứng dụng của nông trại Mc Donald. Trong bài tập tuần này, Mc Donald đang yêu cầu sự giúp đỡ của bạn để giải quyết vấn đề về phả hệ cho đàn gia súc của ông ta, cụ thể như sau:
- Lúc tạo lập nông trại của mình, ông có nhập về những con gia súc giống thuộc 3 loài là Cừu, Bò, Vịt.
- Để tiện cho việc đánh số và quản lý, ứng với mỗi con vật, ông luôn tạo ra một mã định danh cho chúng (ví dụ `B001`, `C001`, `V001`,... với chữ cái đứng đầu đại diện cho mỗi loài)
- Khi các đợt giao phối diễn ra, do số lượng gia súc rất lớn, ông không muốn đàn gia súc của ông xảy ra tình trạng giao phối cận huyết dễ gây ra suy thoái và dẫn đến các tính trạng xấu biểu hiện ra ngày càng mạnh.
- Để ngăn chặn tình trạng này, ông cần phải lưu trữ lại thông tin về gia phả (cha-mẹ ruột, anh-chị-em ruột) cho mỗi con gia súc (Để dễ dàng, ở đây ta giả định rằng những con gia súc giống ban đầu (màu cam) trống hoàn toàn về thông tin gia phả, nét 2 đường đứt biểu hiện cho quan hệ giao phối).
- Cho một ví dụ như sau:
![image](https://hackmd.io/_uploads/Bkl7PXD0a.png)
- Qua hình vẽ trên, ta có thể đặt câu hỏi rằng **Bò cái B014 không thể cho giao phối với những bò đực nào?**...ta dễ thấy:
    - Không thể giao phối với B015 (anh-chị-em)
    - Không thể giao phối với B018 (anh-chị-em)
    - Không thể giao phối với B004 (cha-mẹ)

Bạn sẽ dùng các mẫu thiết kế hướng đối tượng thuộc nhóm tạo lập (Creational Patterns) để tạo ra một ứng dụng Console Application hoặc WPF Application, cài đặt các lớp liên quan để thực hiện một số ràng buộc sau:
- Cho phép nhập vào thông tin các loại gia súc, mã định danh phải được tạo tự động, thông tin về cha mẹ cũng phải được lựa chọn từ danh sách hoặc bỏ trống (nếu là con giống)
- Hiện danh sách các gia súc theo loại, theo quan hệ phả hệ (ví dụ khi chọn bò `B013` phải hiện ra cha là bò `B002`, mẹ là bò `B003`, các anh-chị-em là `B012`, `B010`, `B011` (ở đây là cùng cha khác mẹ), và có 1 con là `B017`)
- Chọn 1 con gia súc bất kì, hiện ra danh sách các con trong đàn có thể giao phối và không thể giao phối
:::

:::danger
:bulb: Một số gợi ý:
- Hãy dùng mẫu Singleton để tạo ra một lớp đối tượng lưu trữ thông tin về mã số hiện tại và sẵn sàng trả về mã số kế tiếp cho loài vật.
- Việc điền các thông tin cho các con vật có thể qua nhiều giai đoạn, hãy dùng mẫu Builder thay vì truyền tất cả thông tin vào constructor.
- Mẫu Prototype sẽ phát huy hiệu quả khi tạo ra nhiều anh-chị-em có chung cha/mẹ.
:::

---

### Buổi 6 (24/03/2024): Các mẫu thiết kế nhóm tạo lập (tt.) và các mẫu thiết kế nhóm cấu trúc
#### 1. Mẫu Prototype + Mẫu Factory
Công ty in ấn sách nhận được đơn hàng in sách số lượng lớn. Công ty nhận được một số bản mẫu và được yêu cầu in ra số lượng bản sao theo yêu cầu với mỗi bản sao sẽ được đánh một số thứ tự riêng biệt với các bản sao khác của cùng một bản mẫu.

Hãy thiết kế một chương trình sử dụng mẫu thiết kế Prototype và Factory để giải quyết vấn đề này. Chương trình cần có các yêu cầu sau:

- Cần có một lớp `BookPrototype` đại diện cho bản mẫu của một cuốn sách, có các thuộc tính như `title` (tiêu đề sách), `author` (tác giả), `category` (thể loại).
- Cần có một lớp `BookFactory` để tạo ra các bản sao của các cuốn sách từ bản mẫu (`BookPrototype`). Mỗi cuốn sách khi được in sẽ được đánh số thứ tự riêng biệt (ví dụ: Book 001, Book 002, ...).

#### 2. Mẫu Adapter
Giả sử bạn có một ứng dụng chuyên dịch tiếng Việt sang tiếng Anh (bạn có sẵn hàm `translateVietnameseToEnglish(string text)` đã được cài đặt rất kỳ công trong mã nguồn.

Một ngày nọ bạn có mua được một thư viện chuyên dịch từ **Tiếng Anh sang nhiều ngôn ngữ khác** nhau (tiếng Hàn, tiếng Tây Ban Nha, tiếng Trung Quốc, tiếng Nhật Bản). Thư viện này cung cấp sẵn một lớp (`TranslationEngService`) chứa các phương thức tĩnh như `translateEnglishToKorean(string text)` ,.... Bạn muốn mở rộng ứng dụng của bạn để hỗ trợ dịch từ **Tiếng Việt sang các ngôn ngữ khác**. Hãy sử dụng mẫu thiết kế Adapter để chuyển đổi từ Tiếng Việt sang Tiếng Anh và sử dụng với thư viện hiện có.

#### 3. Mẫu Bridge
Giả sử bạn đang xây dựng một ứng dụng quản lý tác vụ (Task Management) với nhiều loại tác vụ khác nhau mà trong đó mỗi tác vụ có thể được thực hiện bằng nhiều phương thức triển khai khác nhau, chẳng hạn như triển khai qua email, triển khai qua file, gửi tin nhắn. Hãy sử dụng mẫu thiết kế Bridge để kết nối tác vụ với các phương thức thực hiện.

Yêu cầu:
- Có một lớp `AbstractTask` với phương thức `abstract executeTask()`.
- Có các lớp con `ConcreteTask1`, `ConcreteTask2`, `ConcreteTask3` chỉ các loại công việc cụ thể kế thừa từ `AbstractTask` và triển khai phương thức `executeTask()` theo cách khác nhau.
- Có một lớp `Implementor` với phương thức `abstract doImplementation()`.
- Có các lớp con `EmailImplementor`, `FileImplementor`, `SMSImplementor` triển khai `Implementor` với cách thức thực hiện khác nhau.
- Sử dụng mẫu Bridge để kết nối Task với Implementor.

#### 4. Mẫu Decorator
Giả sử bạn đang xây dựng một ứng dụng gửi tin nhắn và bạn muốn mở rộng chức năng gửi tin nhắn bằng cách thêm tính năng **mã hóa tin nhắn** trước khi gửi. Hãy sử dụng mẫu thiết kế Decorator để thực hiện tính năng này.

Yêu cầu:
- Có một interface `MessageSender` với phương thức `sendMessage(string message)`.
- Có một lớp `SMSMessageSender` triển khai `MessageSender` với phương thức `sendMessage()` để gửi tin nhắn văn bản.
- Có một lớp `MMSMessageSender` triển khai `MessageSender` với phương thức `sendMessage()` để gửi tin nhắn có chứa tập tin đa phương tiện (media).
- Có một lớp Decorator tên là `BaseMessageEncryptorDecorator` triển khai `MessageSender` với phương thức `sendMessage()` để mã hóa tin nhắn trước khi gửi. Ngoài ra có 2 lớp kế thừa nó ứng với 2 phương thức mã hoá là `Method1MessageEncryptorDecorator` và `Method2MessageEncryptorDecorator`.

---

### Buổi 7 (31/03/2024): Các mẫu thiết kế nhóm cấu trúc (tt.)
#### 1. Mẫu Composite
Bạn là chủ của một cửa hàng bán lẻ máy tính và muốn xây dựng một hệ thống để tính tổng giá của các đơn hàng mà khách hàng đặt. Cửa hàng của bạn cung cấp các mặt hàng đơn lẻ như laptop, chuột, bàn phím và cũng có các gói sản phẩm đã được xây dựng trước như "Bộ máy tính gaming", "Bộ máy tính văn phòng", v.v. Bạn muốn khách hàng có thể chọn mua các mặt hàng đơn lẻ hoặc các gói sản phẩm.

Yêu cầu:
- Khi khách hàng đã chọn các mặt hàng hoặc các gói sản phẩm, bạn muốn **tính tổng giá của đơn hàng** để hiển thị cho khách hàng biết trước khi thanh toán.

Ví dụ cụ thể:
- Khách hàng A chọn mua "Bộ máy tính gaming" (bao gồm laptop gaming, chuột cơ, bàn phím cơ). Giá của "Bộ máy tính gaming" là 3000 đơn vị tiền tệ.
- Khách hàng B chọn mua laptop văn phòng và chuột không dây riêng lẻ. Giá của mỗi mặt hàng lần lượt là 1000 và 50 đơn vị tiền tệ. Tổng giá của đơn hàng này là 1050 đơn vị tiền tệ.

#### 2. Mẫu Facade
Bạn là một nhà phân phối vé máy bay và muốn tạo ra một hệ thống đơn giản để giúp khách hàng đặt vé một cách dễ dàng và tiện lợi. Hệ thống của bạn cần gồm ba phần chính:
- Đặt vé: Xử lý việc đặt vé từ khách hàng.
- Thanh toán: Xử lý việc thanh toán cho đơn hàng.
- Xác nhận: Xác nhận và gửi thông tin vé cho khách hàng sau khi đặt vé và thanh toán thành công.

Yêu cầu:
- Lớp `BookingFacade`: che giấu sự phức tạp của các hệ thống con. Lớp này sẽ cung cấp 1 phương thức là `bool BookFlight(string[] seats, string card, string passenger)` (danh sách mã ghế - `seats`, mã thẻ thanh toán `card` và mã hành khách `passenger`) để khách hàng có thể đặt vé máy bay một cách dễ dàng mà không cần quan tâm đến các bước chi tiết.
- Các hệ thống con đã có sẵn bao gồm:
    - `FlightBookingSystem` (hệ thống đặt vé máy bay) - có 3 phương thức là `bool CheckAvailability(string seat)` để kiểm tra xem ghế còn không; `decimal CalculatePrice(string seat)` để kiểm tra giá vé cho ghế mã `seat`, trả về số tiền cần thanh toán; và `void BookASeet(string seat, string passenger)` để ghi lại ghế `seat` đã được hành khách `passenger` đặt thành công.
    - `PaymentSystem` (hệ thống thanh toán) - có phương thức `bool Charge(string card, decimal amount)` để thanh toán số tiền `amount` từ thẻ `card`.
    - `ConfirmationSystem` (hệ thống xác nhận đơn hàng) - có phương thức `void SendComfirmation(string seat, decimal amount, string passenger)`.


#### 3. Mẫu Flyweight
Bạn đang phát triển một trò chơi máy tính với nhiều đối tượng như quái vật hoặc vật phẩm. Mỗi đối tượng này có các thuộc tính như tốc độ, hình dạng, hướng di chuyển, v.v. Trong trường hợp các đối tượng có nhiều phiên bản giống nhau xuất hiện nhiều lần trong một bản đồ, việc tạo mới các đối tượng này mỗi lần chúng xuất hiện sẽ tốn nhiều bộ nhớ.

Yêu cầu:
- Ứng dụng cần quản lý thông tin của nhiều đối tượng trong trò chơi, nhưng không muốn tạo mới các đối tượng này mỗi lần chúng xuất hiện.
- Hãy tạo thử một bản đồ và thêm vào một số đối tượng giống và khác nhau. Hãy xem xem có bao nhiêu đối tượng mỗi loại đang xuất hiện trên bản đồ và bao nhiêu đối tượng thực sự đã được tạo ra.

#### 4. Mẫu Proxy
Bạn đang phát triển một ứng dụng quản lý tệp tin trong hệ thống. Trong hệ thống này, có nhiều tệp tin có độ nhạy cảm và yêu cầu quyền truy cập đặc biệt. Bạn muốn sử dụng mẫu Proxy để kiểm soát quyền truy cập vào các tệp tin này, chỉ cho phép người dùng có quyền hợp lệ truy cập và từ chối người dùng không có quyền.

Yêu cầu:
- Kiểm soát quyền truy cập vào tệp tin: Ứng dụng cần có khả năng kiểm soát quyền truy cập vào các tệp tin trong hệ thống.
- Xác định quyền truy cập của người dùng: Proxy cần xác định quyền truy cập của người dùng và từ chối hoặc cho phép truy cập tương ứng.
- Bảo vệ tệp tin độ nhạy cao: Mục tiêu là bảo vệ các tệp tin độ nhạy cao và chỉ cho phép người dùng có quyền truy cập hợp lệ truy cập vào chúng.

Ví dụ cụ thể
- Người dùng A yêu cầu truy cập vào tệp tin "financial_data.xlsx".
    - Lớp Proxy kiểm tra quyền truy cập của người dùng A.
    - Nếu người dùng A có quyền truy cập vào tệp tin "financial_data.xlsx", Proxy sẽ cho phép truy cập và cung cấp tệp tin cho người dùng A.
    - Nếu người dùng A không có quyền truy cập, Proxy sẽ từ chối truy cập và không cung cấp tệp tin.

- Người dùng B yêu cầu truy cập vào tệp tin "confidential_report.pdf".
    - Lớp Proxy kiểm tra quyền truy cập của người dùng B.
    - Nếu người dùng B có quyền truy cập vào tệp tin "confidential_report.pdf", Proxy sẽ cho phép truy cập và cung cấp tệp tin cho người dùng B.
    - Nếu người dùng B không có quyền truy cập, Proxy sẽ từ chối truy cập và không cung cấp tệp tin.


---

### Buổi 8 (07/04/2024): Các mẫu thiết kế nhóm hành vi và nguyên tắc SOLID
#### 1. Mẫu Command
Trong một ứng dụng quản lý tệp tin, người dùng thường thực hiện các tác vụ như mở, đóng, sao chép và dán tệp tin. Mẫu Command giúp chúng ta quản lý các lệnh này một cách linh hoạt và dễ mở rộng (có khả năng thêm các loại lệnh mới mà không cần sửa đổi nhiều mã nguồn hiện có).

Yêu cầu:
- Tạo một ứng dụng đơn giản để quản lý tác vụ trên tệp tin.
- Sử dụng mẫu Command Pattern để tạo các lệnh để mở, đóng, sao chép và dán tệp tin.

#### 2. Mẫu Iterator
Mẫu thiết kế Iterator được sử dụng để cung cấp một cách truy cập tuần tự và không cần biết cấu trúc bên trong của một tập hợp đối tượng. Ngữ cảnh thường là khi chúng ta muốn duyệt qua các phần tử của một tập hợp (ví dụ: danh sách, mảng, cây) mà không cần phải biết chi tiết về cách tập hợp được triển khai.

Yêu cầu:
- Tạo một lớp chứa dãy số Fibonacci `FibonacciNumbers` lưu lại thông tin về dãy số Fibonacci. (Hãy xem qua [Định nghĩa dãy số Fibonacci trên Wikipedia](https://vi.wikipedia.org/wiki/D%C3%A3y_Fibonacci))
- Tạo một lớp `FibonacciIterator` để duyệt qua các phần tử của một tập hợp số Fibonacci. Lớp Iteratornày sẽ cung cấp các phương thức như `next()` để truy cập phần tử tiếp theo, và `hasNext()` để kiểm tra xem còn phần tử nào khác không.

Sử dụng như sau:
```csharp=
var fibo1 = new FibonacciNumbers(3); // tập hợp fibo1 chứa 3 phần tử đầu tiên của dãy Fibonacci
var fibo2 = new FibonacciNumbers(10); // tập hợp fibo2 chứa 10 phần tử đầu tiên của dãy Fibonacci

var fiboIter1 = new FibonacciIterator(fibo1);
var fiboIter2 = new FibonacciIterator(fibo2);

Console.WriteLine(fiboIter1.next()); // 0
Console.WriteLine(fiboIter1.next()); // 1
Console.WriteLine(fiboIter1.hasNext()); // true
Console.WriteLine(fiboIter1.next()); // 1
Console.WriteLine(fiboIter1.hasNext()); // false
```

#### 3. Mẫu Mediator
Trong một hệ thống nhà thông minh, chúng ta có các thiết bị như đèn và quạt cần điều khiển từ một trung tâm thông minh. Mẫu Mediator giúp chúng ta tạo ra một đối tượng trung gian (Mediator) để điều khiển các thiết bị này một cách linh hoạt và giảm sự phụ thuộc giữa các thiết bị.

Yêu cầu:
- Tạo một đối tượng Mediator để điều khiển và giao tiếp giữa các thiết bị như đèn và quạt.
- Các thiết bị không giao tiếp trực tiếp với nhau mà thông qua Mediator.
- Mediator sẽ cung cấp các phương thức để bật/tắt đèn, bật/tắt quạt...

#### 4. Mẫu Memento
Trong một trò chơi, người chơi thường muốn có khả năng lưu trữ trạng thái hiện tại của trò chơi để sau này có thể khôi phục lại nếu cần. Mẫu thiết kế Memento giúp chúng ta lưu trữ và khôi phục trạng thái của trò chơi một cách linh hoạt và dễ dàng.

Yêu cầu: Trong ví dụ này, chúng ta sẽ tạo một trò chơi lưu trữ trạng thái số điểm và cấp độ của người chơi, sử dụng mẫu thiết kế Memento để lưu trữ và khôi phục trạng thái của trò chơi.

#### 5. SOLID: Tổng quan
:::info
The SOLID acronym stands for:

1. Single Responsibility Principle (SRP)
2. Open-Closed Principle (OCP)
3. Liskov Substitution Principle (LSP)
4. Interface Segregation Principle (ISP)
5. Dependency Inversion Principle (DIP)
:::

---

### Buổi 9 (14/04/2024): Các mẫu thiết kế nhóm hành vi (tt.)
#### 1. Mẫu Observer
Bạn được yêu cầu thiết kế một hệ thống đơn giản để quản lý thông báo cho các người dùng trong một mạng xã hội đơn giản. Các thông báo này được gửi đi từ một người dùng đến các người dùng khác (có đăng ký nhận thông báo từ người dùng đó). Hệ thống cần có khả năng:

- Có khả năng đăng ký và hủy đăng ký để nhận các loại thông báo từ một hoặc nhiều nguồn.
- Khi có thông báo mới từ nguồn nào đó, hệ thống cần cập nhật thông báo mới đến các người dùng đã đăng ký nhận thông báo từ nguồn đó.

:::warning
:bulb: Một người vừa có thể là `Pushlisher` cũng có thể là `Subcriber` của một `Pushlisher` khác. Một người có thể đăng ký nhận thông báo từ nhiều `Pushlisher`. (Hãy nghĩ về mạng xã hội Facebook hoặc Instagram)
:::

#### 2. Mẫu State
Bạn được yêu cầu thiết kế một hệ thống quản lý đặt hàng đơn giản cho một cửa hàng trực tuyến. Hệ thống này sẽ có các trạng thái khác nhau của đơn hàng từ khi được tạo đến khi được giao hàng hoặc hủy bỏ. Các trạng thái bao gồm:

- Đã Tạo (Created): Đơn hàng được tạo, chưa được xác nhận thanh toán.
- Đã Xác Nhận (Confirmed): Đã xác nhận thanh toán, chờ giao hàng.
- Đang Giao (In Transit): Đơn hàng đang được giao đến địa chỉ của khách hàng.
- Đã Giao (Delivered): Đã giao hàng thành công cho khách hàng.
- Đã Hủy (Cancelled): Đơn hàng đã bị hủy.

Hệ thống cần có khả năng hiển thị trạng thái hiện tại của đơn hàng.

:::warning
:bulb: Ví dụ mẫu:
```csharp=
public interface IOrderState
{
    void ConfirmPayment();
    void ShipOrder();
    void DeliverOrder();
    void CancelOrder();
}

// Trạng thái đơn hàng đã được tạo
public class CreatedState : IOrderState
{
    private readonly Order _order;

    public CreatedState(Order order)
    {
        _order = order;
    }

    public void ConfirmPayment()
    {
        Console.WriteLine("Payment confirmed. Order is now being processed.");
        _order.State = new ConfirmedState(_order);
    }

    public void ShipOrder()
    {
        Console.WriteLine("Cannot ship order before payment is confirmed.");
    }

    public void DeliverOrder()
    {
        Console.WriteLine("Cannot deliver order before shipping.");
    }

    public void CancelOrder()
    {
        Console.WriteLine("Order is cancelled.");
        _order.State = new CancelledState(_order);
    }
}
```
:::

#### 3. Mẫu Strategy
Bạn được yêu cầu thiết kế một hệ thống đơn hàng online đơn giản cho một cửa hàng bán hàng điện tử. Hệ thống này sẽ có các chức năng cơ bản như sau:

- Sản Phẩm (Product): Mỗi sản phẩm sẽ có thông tin như tên, giá, và số lượng.
- Đơn Hàng (Order): Mỗi đơn hàng sẽ chứa thông tin về sản phẩm được mua, số lượng, và tổng giá trị đơn hàng.
- Giảm Giá (Discount): Hệ thống có thể áp dụng các loại giảm giá khác nhau cho đơn hàng.

Hệ thống cần có khả năng:

- Tính tổng giá trị của mỗi đơn hàng sau khi áp dụng giảm giá.
- Cho phép thay đổi chiến lược giảm giá một cách linh hoạt, ví dụ như áp dụng giảm giá theo phần trăm, giảm giá cố định, hoặc không giảm giá.

:::warning
:bulb: Ví dụ sử dụng

```csharp=
public class StrategyExample
{
    public static void Main(string[] args)
    {
        // Tạo danh sách sản phẩm
        List<Product> products = new List<Product>
        {
            new Product("Laptop", 1000, 2), // 2 cái laptop, mỗi cái 1000$
            new Product("Mouse", 20, 5), // 5 con chuột, mỗi con 20$
            new Product("Keyboard", 50, 1) // 1 bàn phím, mỗi cái 50$
        };
        
        // Tổng đơn hàng là 2150$

        // Tạo đơn hàng và áp dụng chiến lược giảm giá
        Order order1 = new Order(products, new PercentageDiscountStrategy(10)); // giảm giá 10%
        double totalPrice1 = order1.CalculateTotalPrice();
        Console.WriteLine($"Total Price after 10% discount: ${totalPrice1}");

        // Thay đổi chiến lược giảm giá và tính giá lại
        order1.DiscountStrategy = new FixedDiscountStrategy(50); // giảm giá 50$
        double totalPrice2 = order1.CalculateTotalPrice();
        Console.WriteLine($"Total Price after $50 fixed discount: ${totalPrice2}");

        // Tạo đơn hàng mới và không áp dụng giảm giá
        Order order2 = new Order(products, new NoDiscountStrategy());
        double totalPrice3 = order2.CalculateTotalPrice();
        Console.WriteLine($"Total Price without discount: ${totalPrice3}");
    }
}

/*
 * Total Price after 10% discount: $1935
 * Total Price after $50 fixed discount: $2100
 * Total Price without discount: $2150
 */
```
:::
#### 4. SOLID: Liskov Substitution Principle (LSP)
Nêu ra một ví dụ không tuân thủ nguyên tắc và đề xuất cách chữa.

#### 5. SOLID: Dependency Inversion Principle (DIP)
Nêu ra một ví dụ không tuân thủ nguyên tắc và đề xuất cách chữa.

---

### Buổi 10 (21/04/2024): Các mẫu thiết kế hướng đối tượng và ứng dụng
#### 1. Mẫu Template Method
Cài đặt vào minh hoạ sơ đồ lớp dưới đây

![image](https://hackmd.io/_uploads/rJ0hTafWR.png)

#### 2. Mẫu Visitor
Trong bài toán này, chúng ta cần thiết kế một hệ thống quản lý dịch vụ bảo dưỡng cho các phương tiện giao thông, bao gồm các loại ô tô, xe tải và xe máy. Mỗi phương tiện sẽ được kiểm tra bởi một nhà kiểm tra (`VehicleInspector`) - đây là người sẽ tính toán phí bảo dưỡng cho mỗi loại phương tiện và tổng phí bảo dưỡng cho tất cả các phương tiện.

Dưới đây là cách tính chi phí bảo dưỡng cho mỗi loại phương tiện trong ví dụ này:
- `Car` (thông tin gồm `color` và `manufactureDate`): Chi phí bảo dưỡng cho mỗi chiếc xe ô tô sẽ phụ thuộc vào màu sơn của xe. Nếu màu sơn là "Black", chi phí sẽ là 100 đơn vị, nếu không, chi phí sẽ là 50 đơn vị.
- `Van` (thông tin gồm `storageCapacity` và `numberOfDoors`): Chi phí bảo dưỡng cho mỗi chiếc xe tải sẽ phụ thuộc vào số cửa của xe. Nếu số cửa lớn hơn 4, chi phí sẽ là 500 đơn vị, nếu không, chi phí sẽ là 100 đơn vị.
- `Motorbike` (thông tin gồm `engineCapacity` và `brand`): Chi phí bảo dưỡng cho mỗi chiếc xe máy sẽ phụ thuộc vào dung tích xi-lanh của động cơ. Nếu dung tích xi-lanh lớn hơn hoặc bằng 200, chi phí sẽ là 200 đơn vị, nếu không, chi phí sẽ là 50 đơn vị.


Giả sử ta có 3 chiếc xe:
```csharp=
List<Vehicle> vehicles = new List<Vehicle>() {
    new Car("Black", 2010),  
    new Van(5000, 6),  
    new Motorbike(100, "TVS")  
};



/*
 * Service Charge for Car: 100
 * Service Charge for Van: 500
 * Service Charge for Motorbike: 50
 * Total Service Charge: 650
 */
```

Dưới đây là sơ đồ lớp (chỉ mang tính tham khảo, chưa đúng với chuẩn UML)

![image](https://hackmd.io/_uploads/r1D050GbA.png)

#### 3. Chain of Responsibility
Trong ngữ cảnh rút tiền từ máy ATM, ta có thể ứng dụng mô hình này vào việc xử lý các mệnh giá tiền trả về cho người rút, xem minh hoạ dưới đây:

![image](https://hackmd.io/_uploads/r1i7B0z-A.png)

Ví dụ bạn cần rút 5.000.000Đ, máy ATM chỉ còn lại một số loại tiền với số tờ còn lại tương ứng là: 200.000Đ - 10 tờ, 100.000Đ - 20 tờ. Trong tình huống này, việc rút tiền thất bại do máy không còn đủ tiền chi trả. Hãy xem mỗi khay đựng một mệnh giá là một "chain", hãy sử dụng mô hình này để cài đặt cho bài toán vừa nêu.

#### 4. Mẫu Abstract Factory
Hãy áp dụng mẫu thiết kế Abstract Factory để tạo ra các loại nội thất với chủng loại và kiểu dáng như trong mô tả dưới đây:

![image](https://hackmd.io/_uploads/SyfYLCfbR.png)


#### 5. Mẫu Interpreter
:::info
Học viên tự xem lại ví dụ đã được trình bày trong lớp học.
:::

#### 6. Các mẫu thiết kế hướng đối tượng: Tổng kết
:::success
Học viên sẽ được cung cấp nội dung tóm tắt và PDF của quyển **Design Patterns: Elements of Reusable Object-Oriented Software** *(Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)*.


![GoF](https://hackmd.io/_uploads/r1YqQaGbC.png)
:::

---

## .NET và Ngôn ngữ lập trình C#
### Buổi 11 (05/05/2024): Các khái niệm nâng cao trong C#
:::info
- Delegates
- Events
- Lambda Expressions
- Nullable
- Extension Methods
:::

Tạo một đồng hồ đếm ngược và sử dụng delegate để thông báo một thông điệp cho bất kỳ ai đã "đăng ký" khi đồng hồ chạy hết thời gian. Trong bài tập này, bạn cần cài đặt một lớp đồng hồ đếm ngược nhận vào thông điệp và thời gian đồng hồ cần chạy. Sau khi chạy hết thời gian, bạn sẽ gọi delegate và truyền vào thông điệp để thông báo cho các observers.

Hãy sử dụng biểu thức lambda cho bài tập trên.

:::warning
:bulb: Hãy sử dụng phương thức `Thread.Sleep()` để tạo đồng hồ đếm ngược.
:::

### Buổi 12: Các khái niệm nâng cao trong C# (tt.) - Giới thiệu về kiểm thử đơn vị
:::info
- Exceptions
- Enumeration & Iterators
- Tuples, Records, Anonymous Types
- Patterns (Pattern matching)
- Kiểm thử đơn vị và TDD
:::

Trong bài tập tuần này, bạn được yêu cầu viết kiểm thử đơn vị cho lớp `PhanSo`. Biết rằng trong lớp này, bạn phải cài đặt các phương thức (số trong dấu ngoặc thể hiện cho số yêu cầu có trong mỗi ý):
- (2) Hàm tạo phân số mới (từ tử số và mẫu số nhận vào, từ chuỗi nhận vào - ví dụ `1/5`)
- (4) Cộng/Trừ/Nhân/Chia 2 phân số và trả về phân số mới
- (1) Rút gọn phân số hiện tại
- (1) Quy đồng phân số hiện tại cho `n`
- (1) Đọc một loạt phân số từ một file (phương thức tĩnh, ví dụ `List<PhanSo> DocPhanSo(string inputFile)`)
- (1) Đọc một loạt phân số từ một file (phương thức tĩnh, ví dụ `void GhiPhanSo(List<PhanSo> l, string outputFile)`)
- (6) Toán tử so sánh `>`, `<`, `==`, `>=`, `<=`, `!=`
- (4) Toán tử một ngôi `++`, `--`, `+` và `-`


:::warning
:warning: Chúng ta có tổng cộng 20 yêu cầu.

:warning: Đối với mỗi yêu cầu, bạn cần viết ít nhất 2-3 test cases (bằng framework NUnit)

:bulb: Bạn hãy tham khảo **Operator Overloading** (nạp chồng toán tử) trong C# để có thể nạp chồng các toán tử trong 10 yêu cầu cuối cùng.

:bulb: Ở các yêu cầu viết phương thức cộng, trừ, nhân và chia, bạn cũng có thể cài đặt dưới dạng nạp chồng các toán tử 2 ngôi `+`, `-`, `*` và `/`.

:bulb: Cần lưu ý đến các ngoại lệ có thể xảy ra.
:::

### Buổi 13: .NET cơ bản
:::info
- Attributes
- Dynamic Binding
- Operator Overloading
- Static Polymorphism
- Unsafe code & Pointers
- Preprocessor Directives
- Giới thiệu về .NET
- Các phiên bản mới của C#
- Xử lý chuỗi
- Xử lý ngày tháng và thời gian
- Formatting & Parsing
- Conversions
- Xử lý số học
- Enums
- Guid
- Các phép so sánh và thứ tự
- Các lớp tiện ích cài sẵn
:::

### Buổi 14: Collections
:::info
- Enumeration
- `ICollection` & `IList` Interfaces
- Lớp `Array`
- Lists, Queues, Stacks, Sets
- Dictionaries
- Customizable Collections và Proxies
- Immutable Collections - Frozen Collections
- So sánh và thứ tự
:::

### Buổi 15: Mini-project: Ứng dụng quản lý công việc (To-do App)

Bước đầu để xây dựng nên ứng dụng quản lý công việc là thiết kế sơ đồ lớp cho ứng dụng, cũng như xây dựng lược đồ cho cơ sở dữ liệu. Dưới đây là một số câu chuyện người dùng (user stories) thu thập được trong quá trình phân tích yêu cầu. Hãy sử dụng nó để thiết kế sơ lược nên 2 loại sơ đồ trên

:::info
- Là một người dùng, tôi muốn tạo tài khoản để có thể đăng nhập và truy cập danh sách công việc của mình.
- Là một người dùng, tôi muốn đăng nhập và đăng xuất để công việc của tôi được bảo mật và riêng tư.
- Là một người dùng, tôi muốn tạo một công việc mới để có thể theo dõi những việc cần làm.
- Là một người dùng, tôi muốn chỉnh sửa công việc để có thể cập nhật thông tin hoặc sửa lỗi sai.
- Là một người dùng, tôi muốn xóa công việc để có thể loại bỏ những công việc không còn cần thiết.
- Là một người dùng, tôi muốn đánh dấu công việc đã hoàn thành để có thể thấy được tiến độ của mình.
- Là một người dùng, tôi muốn xem lại các công việc đã hoàn thành để có thể đánh giá những gì đã làm được.
:::

---

## Cơ sở dữ liệu
### Buổi 16: Tổng quan về CSDL, CSDL quan hệ và các hệ quản trị CSDL quan hệ

### Buổi 17: MS SQL Server và truy vấn cơ bản

### Buổi 18: Truy vấn nâng cao

### Buổi 19: Lập trình trong CSDL

### Buổi 20: Một số vấn đề của CSDL quan hệ, CSDL phi quan hệ

---

## LINQ và Entity Framework
### Buổi 21: Truy vấn bằng LINQ

### Buổi 22: XML và JSON

### Buổi 23: Entity Framework

### Buổi 24: Entity Framework (tt.)

### Buổi 25: Mini-project: Ứng dụng quản lý thú cưng

---

## Các chủ đề nâng cao trong lập trình
### Buổi 26: Lập trình đa luồng (Multithreaded programming) và lập trình bất đồng bộ (Asynchronous programming)

### Buổi 27: I/O và Streams

### Buổi 28: Networking

### Buổi 29: Reflection, Metadata & Assemblies

### Buổi 30: Dynamic Programming, Cryptography, Advanced Threading & Parallel Programming

### Buổi 31: Mini-project: Lập trình ứng dụng Server

### Buổi 32: Mini-project: Lập trình ứng dụng Client

### Buổi 33: Kiến trúc phần mềm

### Buổi 34: Kiến trúc phần mềm (tt.)

### Buổi 35: Kiến trúc phần mềm (tt.)

---

## Lập trình giao diện với WPF
### Buổi 36: Data binding

### Buổi 37: Controls

### Buổi 38: Animations

### Buổi 39: UI & UX

### Buổi 40: UI & UX (tt.)

### Buổi 41: Đóng gói phần mềm

### Buổi 42: Best practices

### Buổi 43: Best practices (tt.)

### Buổi 44: Performance Tuning

### Buổi 45: Performance Tuning (tt.)

### Buổi 46: Kiểm thử phần mềm

### Buổi 47: Kiểm thử phần mềm (tt.)

### Buổi 48 & 49 & 50: Big-project: Ứng dụng quản lý trang trại

---

## Clean Code
### Buổi 51: Refactoring

...
