Chuyển đến nội dung chính

Strategy Pattern


Strategy Pattern là một thuật toán dễ hiểu, dễ ứng dụng và vô cùng mạnh mẽ. Đây là thuật toán đầu tiên mà tôi viết trong 1 loạt bài tìm hiểu về Design Patterns.

Định nghĩa

Một định nghĩa không chính thức về Strategy Pattern (Phương pháp chiến lược) là:
Định nghĩa tập hợp các thuật toán, đóng gói từng thuật toán lại, và làm chúng hoán đổi lẫn nhau. Strategy cho phép thuật toán biến đổi độc lập khi người dùng sử dụng chúng.(1)
Một cách hiểu đơn giản hơn: Đây là mẫu thiết kế giúp bạn trừu tượng hóa những hành vi (behavior, method, function) của một đối tượng bằng cách đưa ra những cài đặt vào những lớp khác nhau.
Giả sử chúng ta nhận được yêu cầu viết 1 chương trình để đọc file txt. Rồi sau đó yêu cầu phát sinh, chúng ta phải viết các hàm đọc file csv, xls… Chúng ta không thể viết như thể viết các method lần lượt là:
public void ReadText(){…}
public void ReadExcel(){…}

Phương pháp này giúp bạn giải quyết nhanh vấn đề trong bài toán nhỏ. Nhưng 1 khi project của bạn lớn theo từng ngày, bạn không thể viết theo kiểu lập trình thủ tục này được. Nó tiềm ẩn nhiều rủi ro và vi phạm nguyên tắc hướng đối tượng: Open For Extension and Close For Modification.
Bạn thử tưởng tượng xem, nếu chương trình bạn có khả năng đọc tới 100 files, bạn sẽ có 100 methods, và mình nghĩ là bạn sẽ rối và khó quản lý chúng.

Khi nào sử dụng Strategy Pattern

  • Nhiều class có liên quan với nhau chỉ khác nhau về hành vi. Dựa vào Strategy Pattern, ta xây dựng được 1 class cấu hình với 1 trong các hành vi đó.
  • Bạn cần biến thể khác nhau của 1 thuật toán.
    Ví dụ: Trước đây bạn dùng thuật toán MD5 để mã hóa dữ liệu. Sau này do nhu cầu thay đổi, bạn muốn dùng thuật toán SHA1 nhưng vẫn muốn giữ lại MD5.
  • Tạo giao diện sử dụng đơn giản, tránh đưa ra những chi tiết không cần thiết cho người sử dụng.
  • Một class với nhiều hành vi, và sẽ xuất hiện nhiều lần trong câu lệnh điều kiện. Thay vì chọn lựa behaviour khi thi hành, di chuyển các nhánh liên quan vào trong lớp Strategy của riêng nó.

Ứng dụng

Đây là bài ví dụ của anh Nguyễn Văn Thoại, mình xin mượn đỡ ý tưởng để minh họa:
Giả sử tôi có 1 cô bạn nữ. Vào những ngày cuối tuần, tôi thường dẫn cô ấy đi chơi giải trí. Tất nhiên đi chơi phải có chiến lược (strategy), nếu không thì sớm gặp thất bại. Tôi đã vạch sẵn trong đầu (server), hàng tá kế hoạch đi chơi (many algorithms). Tham khảo nguyên nhân thất bại 2 lần trước:
  • Lần 1: Tôi chỉ cài đặt 1 hàm đi chơi, và mỗi lần muốn tìm chỗ mới, tôi ngồi sửa hàm. Sửa kịp thì không sao. Sửa không kịp thì tới ngày đi chơi, tôi đành cancel. Phương pháp này chiếm tỉ lệ thất bại hơn 75%.
  • Lần 2: Tôi quyết định thay đổi hàm đi chơi. Thay vì viết 1 hàm, tôi viết hơn sẵn 1 chục hàm. Tới khi gặp cô ấy, tôi đưa ra nhiều lời đề nghị, nhưng hình như cô ấy không vui vì tôi luôn áp đặt nhiều cách đi chơi mà cô ấy không thích. Tỷ lệ thành công 50-50
Sau nhiều ngày vắt óc, tôi quyết định thay đổi tư tưởng khi đi chơi. Đi chơi phải đơn giản, và cho người ta quyết định đi chơi ở đâu, không phải là mình đưa ra rồi bảo người ta chọn.
Để đơn giản, tôi quyết định dùng 1 hàm duy nhất là Đi Chơi() để bạn ấy khỏi lựa chọn nhiều (lựa chọn về nhà :(( là tiêu). Để bạn ấy tùy hứng theo tâm trạng mà chọn tiết mục đi chơi nào, tôi quyết định cài đặt sẵn 1 số ý tưởng (implement interface), rồi tùy theo tình huống (runtime), cô ấy sẽ quyết định sẽ chọn Cách đi chơi nào (behaviour). Oh, tôi sung sướng thốt lên: Eureka. (Ý đừng có nhìn tôi tiếp nha).
Kế hoạch đi chơi

 Hàm Dẫn Bạn Gái Đi Chơi có duy nhất 1 phương thức: Đi chơi. (Đảm bảo tính đơn giản).
    public interface ICachDiChoi
    {
        void DiChoi();
    }
    public class DiUongNuoc: ICachDiChoi
    {
        public void DiChoi()
        {
            Console.WriteLine("Di uong nuoc");
        }
    }
...
    public class AnBinhTrong: IHuman
    {
        private readonly ICachDiChoi _cachDiChoi;

        public AnBinhTrong(ICachDiChoi cachDiChoi)
        {
            _cachDiChoi = cachDiChoi;
        }

        public void DanBanGaiDiChoi()
        {
            _cachDiChoi.DiChoi();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var abt = new AnBinhTrong(new DiUongNuoc());
            abt.DanBanGaiDiChoi();
        }
    }
Source code: Mediafire
 --------------
1: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.