Strategy Pattern xây dựng chiến lược trong lúc chạy
NỘI DUNG BÀI VIẾT
1. Strategy Pattern là gì?
Tần suất sử dụng: 4/5, Strategy pattern được sử dụng khá nhiều trong lập trình.
Mỗi dạng Design Pattern sẽ giới thiệu một Pattern tiêu biểu và Behavioral Design Pattern sẽ được bàn luận với pattern cuối cùng là Strategy pattern, mẫu này áp dụng khi làm việc với các hành vi của đối tượng, nó “đánh dấu” cách ứng dụng chạy. Factory pattern có thể thay đổi dạng đối tượng thì Strategy có thể thay đổi thuật toán (hành vi) của đối tượng. Strategy rất hữu ích trong một số trường hợp nơi mà các class là tương tự nhau nhưng không liên quan và khác nhau về hành vi. Ví dụ, chúng ta cần lọc các chuỗi, các bộ lọc khác nhau có thể sử dụng:
- Loại bỏ các thẻ HTML
- Loại bỏ các từ ngữ không phù hợp.
- Loại bỏ các ký tự sử dụng để gửi thư rác thông qua hình thức liên lạcThông thường chúng ta sẽ làm 3 giải pháp và áp dụng chúng vào các chuỗi cần lọc. Các bộ lọc có thể được áp dụng một cách khác nhau. Đầu tiên, định nghĩa interface với các tính năng cần thiết
interface Filter {
function filter($str);
}
Code language: PHP (php)
Xác định dạng bộ lọc sau đó implement các phiên bản thích hợp của phương thức trong interface:
class HtmlFilter implements Filter {
function filter($str) {
// Loại bỏ mã HTML
return $str;
}
}
class SwearFilter implements Filter {
function filter($str) {
// Loại bỏ các từ ngữ không phù hợp.
return $str;
}
}
Code language: PHP (php)
Cuối cùng, sử dụng bộ lọc trong một class khác.
<pre class="prettyprint prettyprinted"><span class="kwd">class</span> <span class="typ">FormData</span> <span class FormData {
private $_data = NULL;
function __construct($input) {
$this->_data = $input;
}
function process(Filter $type) {
$this->_data = $type->filter($this->_data);
}
}
Code language: JavaScript (javascript)
Phương thức process() nhận một đối tượng dạng Filter và thông qua đó dữ liệu được lọc.
$form = new FormData($someUserInput);
if (!$allowHTML) {
$form->process(new HtmlFilter());
}
if (!allowSwear) {
$form->process(new SwearFilter());
}
Code language: PHP (php)
2. Ví dụ áp dụng Strategy Pattern trong PHP
OK, lý thuyết là như vậy, chúng ta cùng áp dụng vào thực tế, ví dụ về một ứng dụng quản lý sinh viên. Tạo ra file strategy.php trong oop\pattern với nội dung:
<!doctype html>
<html lang="vi">
<head>
<meta charset="utf-8">
<title>Ví dụ về Strategy pattern</title>
</head>
<body>
<?php
// Interface Sort định nghĩa phương thức sort()
interface iSort {
function sort(array $list);
}
// Lớp MultiAlphaSort sắp xếp mảng đa chiều chứa ký tự
class MultiAlphaSort implements iSort {
// Cách sắp xếp: tăng dần, giảm dần
private $_order;
// Sort index:
private $_index;
function __construct($index, $order = 'ascending') {
$this->_index = $index;
$this->_order = $order;
}
// Phương thức thực hiện sắp xếp
function sort(array $list) {
// Change the algorithm to match the sort preference:
if ($this->_order == 'ascending') {
uasort($list, array($this, 'ascSort'));
} else {
uasort($list, array($this, 'descSort'));
}
return $list;
}
// Phương thức so sánh hai giá trị
function ascSort($x, $y) {
return strcasecmp($x[$this->_index], $y[$this->_index]);
}
function descSort($x, $y) {
return strcasecmp($y[$this->_index], $x[$this->_index]);
}
}
// Class MultiNumberSort sắp xếp một mảng đa chiều
class MultiNumberSort implements iSort {
// Cách sắp xếp
private $_order;
// Sort index
private $_index;
function __construct($index, $order = 'ascending') {
$this->_index = $index;
$this->_order = $order;
}
// Thực hiện sắp xếp
function sort(array $list) {
// Thay đổi thuật toán phù hợp với thiết lập
if ($this->_order == 'ascending') {
uasort($list, array($this, 'ascSort'));
} else {
uasort($list, array($this, 'descSort'));
}
return $list;
}
// Phương thức so sánh hai giá trị
function ascSort($x, $y) {
return ($x[$this->_index] > $y[$this->_index]);
}
function descSort($x, $y) {
return ($x[$this->_index] < $y[$this->_index]);
}
}
/* Lớp StudentsList
* Lớp có 1 thuộc tính: _students.
* Lớp có 3 phương thức:
* - __construct()
* - sort()
* - display()
*/
class StudentsList {
// Danh sách sinh viên được sắp xếp
private $_students = array();
function __construct($list) {
$this->_students = $list;
}
// Thực hiện sắp xếp sử dụng một thực thi từ iSort
function sort(iSort $type) {
$this->_students = $type->sort($this->_students);
}
// Hiển thị danh sách sinh viên dạng HTML
function display() {
echo '<ol>';
foreach ($this->_students as $student) {
echo "<li>{$student['last_name']} {$student['first_name']} : {$student['grade']}</li>";
}
echo '</ol>';
}
}
// Tạo mảng sinh viên, mỗi sinh viên có cấu trúc studentID => array('first_name' => 'First Name', 'last_name' => 'Last Name', 'grade' => XX.X)
$students = array(
256 => array('first_name' => 'Tuấn', 'last_name' => 'Trần Đăng', 'grade' => 98.5),
2 => array('first_name' => 'An', 'last_name' => 'Nguyễn Xuân', 'grade' => 85.1),
9 => array('first_name' => 'Dương', 'last_name' => 'Nguyễn Ngọc', 'grade' => 94.0),
364 => array('first_name' => 'Chiến', 'last_name' => 'Hoàng Văn', 'grade' => 85.1),
68 => array('first_name' => 'Phương', 'last_name' => 'Trần Thanh', 'grade' => 74.6)
);
// Tạo đối tượng
$list = new StudentsList($students);
// Hiển thị mảng trước khi sắp xếp
echo '<h2>Danh sách gốc</h2>';
$list->display();
// Sắp xếp theo tên
$list->sort(new MultiAlphaSort('first_name'));
echo '<h2>Danh sách sắp xếp theo tên</h2>';
$list->display();
// Sắp xếp theo điểm
$list->sort(new MultiNumberSort('grade', 'descending'));
echo '<h2>Danh sách sắp xếp theo điểm</h2>';
$list->display();
// Xóa đối tượng
unset($list);
?>
</body>
</html>
Code language: HTML, XML (xml)
Trong ví dụ này chúng ta thấy rằng cùng là hành vi sort() nhưng nó khác nhau ở các thời điểm khác nhau, chỗ thì sắp xếp tên, chỗ thì sắp xếp điểm. Như vậy việc áp dụng Strategy Pattern giúp chúng ta thay đổi được hành vi của một đối tượng trong thời gian chạy. Kết quả khi thực hiện trong trình duyệt như sau:

Cảm ơn các bạn đã đọc.
Các bạn có thể tham khảo các bài viết hay về Laravel tại đây.
Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.
Nguồn tham khảo: Allaravel
Leave a Reply