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

Strategy Pattern trong iOS

0 0 19

Người đăng: Kiên HT

Theo Viblo Asia

Độ khó: Beginner | Easy | Normal | Challenging
Xcode 14.0.1
Swift 5.7


1. Giới thiệu 👋

Trong bài viết này mình sẽ giới thiệu đến các bạn một Fundamental Design Pattern - Strategy Pattern. Vậy Strategy Pattern là một pattern như thế nào, ứng dụng và cách cài đặt nó như thế nào?


Theo cá nhân mình thì học Design Pattern khá là khô khan và khó hiểu. Nên mình sẽ không nói về lý thuyết/định nghĩa ngay. Mình sẽ trình bày một ví dụ về Strategy Pattern trước, sau đó chúng ta sẽ đi sâu vào xem bản chất của nó nhé !!!

2. Ví dụ về Strategy Pattern 😎

  • Đầu tiên, mình có 1 protocol tên là Strategy có một hàm execute với 2 tham số a và b. Còn làm gì với 2 tham số này thì protocol Strategy không quan tâm nhé (Tất nhiên rồi, vì đã được protocol này trừu tượng hoá rồi)
protocol Strategy { func execute(a: Int, b: Int)
}

  • Phần tiếp theo mình sẽ có 3 class conform / implement protocol Strategy:
class ConcreteStrategyAdd: Strategy { func execute(a: Int, b: Int) { print("a + b = \(a + b)") }
} class ConcreteStrategySubtract: Strategy { func execute(a: Int, b: Int) { print("a - b = \(a - b)") }
} class ConcreteStrategyMultiply: Strategy { func execute(a: Int, b: Int) { print("a * b = \(a * b)") }
}

=> Nhìn vào code trên thì chúng ta cũng sẽ hiểu được tác dụng của 3 hàm trên là gì phải không mọi người. Gồm 3 hàm mô tả: tổng 2 số a và b, hiệu 2 số a và b, tích 2 số a và b.


  • Và chúng ta có 1 phần cuối cùng là class Context chứa protocol Strategy. Lưu ý quan trọng là class Context chứa protocol Strategy chứ không hề chứa 1 trong 3 class cụ thể ConcreteStrategy nhé.
class Context { private var strategy: Strategy? func setStrategy(_ strategy: Strategy) { self.strategy = strategy } func executeStrategy(a: Int, b: Int) { strategy?.execute(a: a, b: b) }
}

  • Bây giờ chúng ta đã có đủ 3 thành phần cấu tạo nên Strategy Pattern, mình sẽ trình bày cách sử dụng pattern này cho mọi người ngay sau đây:
let context = Context()
context.setStrategy(ConcreteStrategyAdd())
context.executeStrategy(a: 10, b: 5) // a + b = 15 context.setStrategy(ConcreteStrategySubtract())
context.executeStrategy(a: 10, b: 5) // a - b = 5 context.setStrategy(ConcreteStrategyMultiply())
context.executeStrategy(a: 10, b: 5) // a * b = 50
  • Từ ví dụ trên chúng ta có thể hình dung qua về pattern này rồi phải không. Cùng là 1 class Context, nhưng khi được áp dụng "chiến thuật" cộng 2 số a và b (ConcreteStrategyAdd) thì khi chạy hàm executeStrategy của class Context, chúng ta sẽ được kết quả là: a + b = 15
  • Đồng thời, cũng trong lúc chạy class Context này, nếu mình áp dụng "chiến thuật" khác cho class. Ví dụ như "chiến thuật" hiệu 2 số a và b (ConcreteStrategySubtract), hoặc "chiến thuật" lấy tích 2 số a và b (ConcreteStrategyMultiply). Chúng ta sẽ được kết quả tương ứng như example code của mình nhé.

3. Strategy Pattern là gì? 🤔

  • Strategy Pattern thuộc nhóm Behavioral Design Pattern. Nó sẽ định nghĩa nhiều đối tượng (mà những đối tượng này có thể hoán đổi cho nhau) ở những class khác nhau. Đồng thời có thể thay đổi cho nhau trong run time của chương trình.
  • The strategy pattern defines a family of interchangeable objects that can be set or switched at runtime - Design Pattern by Tutorials
  • Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable - Dive Into Design Pattern

Đó là một số định nghĩa của Strategy Pattern. Nếu mọi người vẫn thấy khó hiểu thì mình sẽ giải thích sơ qua như thế này:

  • Strategy Pattern nó sẽ gồm 3 phần (như ảnh hoặc ví dụ ở phần 2):
    • Một protocol Strategy chứa những hàm mà chúng ta cần sử dụng (tương ứng với ô vuông "<<Protocol>> Strategy Protocol")
    • Một class Context chứa protocol Strategy ở trên (tương ứng với ô vuông "Object using a Strategy"
    • Và những class conform Strategy (những class này gọi là Concrete Strategy là những class có những hành vi/chiến thuật khác nhau). Chúng cần conform Strategy để có thể truyền vào class Context ở trên. Và vì chúng đều conform protocol Strategy nên chúng có thể thay đổi / hoán đổi cho nhau trong runtime của chương trình

=> Note: từ khoá quan trọng trong Strategy Pattern là những "chiến thuật" (Concrete Strategy) này có thể thay đổi trong RUNTIME nhé mọi người.

4. Khi nào thì sử dụng Strategy Pattern? ⏳️

  • Sử dụng Strategy Pattern khi bạn có 2 hay nhiều biến thể trong cùng 1 đối tượng (những biến thể đó có các hành vi khác nhau). Và những biến thể đó có thể thay đổi cho nhau trong runtime.
  • Use the strategy pattern when you have two or more different behaviors that are interchangeable. - Design Pattern by Tutorials
  • Use the Strategy pattern when you want to use different variants of an algorithm within an object and be able to switch from one algorithm to another during runtime. - Dive Into Design Pattern

5. Ưu và nhược điểm 🤙

5.1. Ưu điểm

  • Có thể thay đổi các thuật toán / hành vi trong đối tượng trong suốt giai đoạn runtime.
  • Có thể tách biệt việc triển khai chi tiết (implementation) của thuật toán / hành vi ra khỏi code sử dụng nó ( ở ví dụ 2 chúng ta đã tách việc implementation - 3 class Concrete ra khỏi code sử dụng nó - class Context)
  • Khi chúng ta dùng Strategy Pattern, chúng ta đã sử dụng composition thay cho inheritance
  • Đúng với nguyên lý Open/Closed Principle (nguyên lý O trong SOLID). Khi chúng ta muốn thêm 1 thuật toán / hành vi, chúng ta sẽ không cần sửa dụng thuật toán / hành vi đã có.

5.2. Nhược điểm

  • Nếu chúng ta chỉ có 2 hoặc ít thuật toán / hành vi, và chúng không thay đổi trong quá trình runtime. Thì không nên sử dụng Strategy Pattern nhé, việc sử dụng Strategy Pattern trong trường hợp này sẽ làm phức tạp hoá vấn đề không cần thiết
  • Người dùng / lập trình viên phải biết + hiểu được sự khác nhau giữa các thuật toán / hành vi để chọn cho đúng thuật toán / hành vi để sử dụng.
  • Việc tạo thêm class để tạo ra thuật toán / hành vi nhiều khi không cần thiết. Vì trong một số ngôn ngữ đã có hàm ẩn danh (anonymous function) để giúp thực hiện việc này.

6. Kết luận 📔

  • Vậy là chúng ta đã tìm hiểu xong Strategy Pattern là gì và cách cài đặt nó như thế nào thông qua blog này.
  • Nếu các bạn có thắc mắc hay có cách nào tối ưu được ví dụ Strategy Pattern của mình thì đừng ngần ngại hãy comment nhé. Mình cảm ơn các bạn rất nhiều.

Ngoài ra có thể đọc thêm 1 số ví dụ về Strategy Pattern:

Reference 🥳

Bình luận

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

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

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 253

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

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

0 0 189

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

Swift: Tạo custom phép toán tử (Operator) của riêng bạn!

Swift cho phép bạn tạo các toán tử có thể tùy chỉnh của riêng bạn. Điều này đặc biệt hữu ích khi bạn xử lý các loại dữ liệu của riêng mình. Operator Types in Swift. Có năm loại toán tử chính trong Swift.

0 0 45

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

Chương 6 Protocol oriented programming.

Cuốn sách này là về lập trình hướng protocol. Khi Apple thông báo swift 2 ở WWDC 2015.

0 0 27

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

Ví dụ về UIActivityViewController

Trên iOS, UIActivityViewController cung cấp giao diện thống nhất để người dùng chia sẻ và thực hiện các hành động trên văn bản, hình ảnh, URL và các mục khác trong ứng dụng. let string = "Hello, world!". let url = URL(string: "https://nshipster.com").

0 0 45

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

Quản lý self và cancellable trong Combine.

. . Công việc quản lý bộ nhớ memory management thường trở nên phức tạp khi chúng ta thực hiện các tác vụ bất đồng bộ asynchronous vì chúng ta thường phải lưu giữ một số object nằm ngoài scope mà object được define trong khi vẫn phải đảm bảo được việc giải phóng object đó được thực hiện đúng quy trìn

0 0 28