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

[Design Patterns] Strategy Pattern

0 0 27

Người đăng: Thịnh Trần

Theo Viblo Asia

Strategy (kế hoạch) được sử dụng khi chúng ta muốn triển khai một class có phương thức hoạt động có thể được lựa chọn ở thời điểm phần mềm đang vận hành runtime. Strategy được xếp vào nhóm các pattern Hành Vi.

Áp dụng triển khai

Khá giống với [State] mà chúng ta đã đề cập tới trong bài viết gần đây - [Design Patterns] State Patter - Strategy được sử dụng để triển khai tính đa hình trong kiến trúc phần mềm thay vì trong tính năng của ngôn ngữ.

Điểm khác biệt cơ bản so với State, đó là Strategy tập trung vào câu hỏi "Kế hoạch hoạt động là gì?" hay "Việc cần làm là gì?". Trong khi đó thì State lại tập trung vào câu hỏi "Thực hiện như thế nào trong tình huống này?"

sơ đồ các class

Trong bài viết trước đó về State, chúng ta đã lấy ví dụ về phiên bản desktop của một phần mềm quản lý blog với "Việc cần làm" đã được xác định trước. Đó là phương thức save() thực hiện tác vụ lưu trữ bài viết Post mà người dùng đang soạn thảo. Tuy nhiên việc phương thức này hoạt động "như thế nào?" thì lại phụ thuộc vào trạng thái State của Post. Hay nói một cách khác là cách thức thực hiện công việc save() sẽ thay đổi tùy thuộc vào trạng thái của Post.

Trong bài viết này chúng ta có Strategy và vẫn lấy ví dụ về phần mềm quản lý blog ở trên. Giả định rằng người dùng đang ở giao diện quản lý danh sách các bài viết và có thể đánh dấu chọn nhiều bài viết để thực hiện một thao tác nào đó: Đăng tải, Gỡ bài viết, hoặc Xóa bài viết. Lúc này "Việc cần làm" đối với các bài viết được đánh dấu lại chưa được xác định trước và chỉ ở thời điểm người dùng nhấn vào danh sách "Thao tác" để lựa chọn và nhấn nút "Áp dụng" thì chúng ta mới biết được "Việc cần làm là gì?".

Bước 1

Tạo class Post mô tả thực thể các bài viết.

strategypattern/Post.java

package strategypattern; public class Post { private String title; private String author; private String status; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; }
}

Bước 2

Tạo interface Strategy làm giao diện chung cho các kế hoạch hay các thao tác với phương thức apply().

strategypattern/Strategy.java

package strategypattern; import java.util.List; public interface Strategy { public void apply(List<Post> selectedPosts);
}

Bước 3

Tạo ra các kế hoạch hay các thao tác cụ thể để áp dụng cho các Post được đánh dấu.

Thao tác "Đăng tải" Publish sẽ gắn nhãn "Đã đăng tải" cho các Post và in thông báo ra console.

strategypattern/Publish.java

package strategypattern; import java.util.List; public class Publish
implements Strategy { @Override public void apply(List<Post> selectedPosts) { // với mỗi post đã được chọn // gắn nhãn Đã đăng tải // và in ra thông báo selectedPosts.stream().forEach((post) -> { post.setStatus("Đã đăng tải"); System.out.println( "Bài viết [" + post.getTitle() + " - " + post.getAuthor() + "] đã được cập nhật và đăng tải." ); }); }
}

Thao tác "Gỡ bài" Unpublish sẽ gắn nhãn "Bản nháp" cho các Post và in thông báo ra console.

stategypattern/Unpublish.java

package strategypattern; import java.util.List; public class Unpublish
implements Strategy { @Override public void apply(List<Post> selectedPosts) { // với mỗi post đã được chọn // gắn nhãn Bản nháp // và in ra thông báo selectedPosts.stream().forEach((post) -> { post.setStatus("Bản nháp"); System.out.println( "Bài viết [" + post.getTitle() + " - " + post.getAuthor() + "] đã được gỡ xuống và lưu nháp." ); }); }
}

Thao tác "Xóa bài" Remove sẽ gắn nhãn "Đã xóa gần đây" cho các Post và in thông báo ra console.

strategypattern/Remove.java

package strategypattern; import java.util.List; public class Remove
implements Strategy { @Override public void apply(List<Post> selectedPosts) { // với mỗi post đã được chọn // gắn nhãn Đã xóa gần đây // và in thông báo selectedPosts.stream().forEach((post) -> { post.setStatus("Đã xóa gần đây"); System.out.println( "Bài viết [" + post.getTitle() + " - " + post.getAuthor() + "] đã được tạm xóa. " + "Hệ thống sẽ xóa bài viết sau 30 ngày." ); }); }
}

Bước 4

Giả định cơ sở dữ liệu để sử dụng trong code main với một vài bài viết đã được người dùng soạn thảo.

PatternDemo.java

import strategypattern.*; import java.util.ArrayList;
import java.util.List; public class PatternDemo { private static List<Post> database; public static void main(String[] args) { connectDatabase(); } private static void connectDatabase() { database = new ArrayList<Post>(); Post designPatterns = new Post(); designPatterns.setTitle("Giới Thiệu Design Patterns"); designPatterns.setAuthor("Semi Art"); designPatterns.setStatus("Đã đăng tải"); database.add(designPatterns); Post statePattern = new Post(); statePattern.setTitle("State Pattern"); statePattern.setAuthor("Semi Art"); statePattern.setStatus("Đã đăng tải"); database.add(statePattern); Post strategyPattern = new Post(); strategyPattern.setTitle("Strategy Pattern"); strategyPattern.setAuthor("Semi Art"); strategyPattern.setStatus("Bản nháp"); database.add(strategyPattern); }
}

Bước 5

Giả lập các thao tác người dùng để kiểm tra hoạt động của Strategy Pattern.

PatternDemo.java

import strategypattern.*; import java.util.ArrayList;
import java.util.List; public class PatternDemo { private static List<Post> database; public static void main(String[] args) { connectDatabase(); // giả định người dùng đánh dấu chọn vài bài viết List<Post> selectedPosts; // object mô tả thao tác được chọn để áp dụng với các post được đánh dấu Action action = new Action(); System.out.println("========== Thao tác người dùng 1"); // người dùng chọn 2 bài viết "State" và "Strategy" selectedPosts = selectTwoLatestPosts(); // người dùng nhấn vào danh sách "Thao tác" và chọn "Gỡ bài viết" action.setStrategy(new Unpublish()); // người dùng nhấn vào nút "Áp dụng" để thực hiện thao tác vừa chọn action.apply(selectedPosts); System.out.println("========== Thao tác người dùng 2"); // người dùng chọn bài viết "Giới Thiệu Design Patterns" selectedPosts = selectFirstPost(); // người dùng nhấn vào danh sách "Thao tác" và chọn "Xóa bài viết" action.setStrategy(new Remove()); // người dùng nhấn vào nút "Áp dụng" để thực hiện thao tác vừa chọn action.apply(selectedPosts); System.out.println("========== Thao tác người dùng 3"); // người dùng lại chọn 2 bài viết "State" và "Strategy" selectedPosts = selectTwoLatestPosts(); // người dùng nhấn vào danh sách "Thao tác" và chọn "Đăng tải bài viết" action.setStrategy(new Publish()); // người dùng nhấn vào nút "Áp dụng" để thực hiện thao tác vừa chọn action.apply(selectedPosts); } private static void connectDatabase() { ... } private static List<Post> selectFirstPost() { return database.stream() .filter((post) -> post.getTitle().equalsIgnoreCase("giới thiệu design patterns")) .toList(); } private static List<Post> selectTwoLatestPosts() { return database.stream() .filter((post) -> post.getTitle().equalsIgnoreCase("state pattern") || post.getTitle().equalsIgnoreCase("strategy pattern") ) .toList(); }
}

Bước 6

Kiểm chứng lại kết quả được in ra ở console.

console

========== Thao tác người dùng 1
Bài viết [State Pattern - Semi Art] đã được gỡ xuống và lưu nháp.
Bài viết [Strategy Pattern - Semi Art] đã được gỡ xuống và lưu nháp.
========== Thao tác người dùng 2
Bài viết [Giới Thiệu Design Patterns - Semi Art] đã được tạm xóa. Hệ thống sẽ xóa bài viết sau 30 ngày.
========== Thao tác người dùng 3
Bài viết [State Pattern - Semi Art] đã được cập nhật và đăng tải.
Bài viết [Strategy Pattern - Semi Art] đã được cập nhật và đăng tải.

Bình luận

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

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

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 67

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

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 47

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

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 41

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

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 75

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

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 280

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

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 50