[Design Patterns] Strategy Pattern

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 đã đề

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

packagestrategypattern;publicclassPost{privateString title;privateString author;privateString status;publicStringgetTitle(){return title;}publicvoidsetTitle(String title){this.title = title;}publicStringgetAuthor(){return author;}publicvoidsetAuthor(String author){this.author = author;}publicStringgetStatus(){return status;}publicvoidsetStatus(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

packagestrategypattern;importjava.util.List;publicinterfaceStrategy{publicvoidapply(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

packagestrategypattern;importjava.util.List;publicclassPublishimplementsStrategy{@Overridepublicvoidapply(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

packagestrategypattern;importjava.util.List;publicclassUnpublishimplementsStrategy{@Overridepublicvoidapply(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

packagestrategypattern;importjava.util.List;publicclassRemoveimplementsStrategy{@Overridepublicvoidapply(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

importstrategypattern.*;importjava.util.ArrayList;importjava.util.List;publicclassPatternDemo{privatestaticList<Post> database;publicstaticvoidmain(String[] args){connectDatabase();}privatestaticvoidconnectDatabase(){
      database =newArrayList<Post>();Post designPatterns =newPost();
      designPatterns.setTitle("Giới Thiệu Design Patterns");
      designPatterns.setAuthor("Semi Art");
      designPatterns.setStatus("Đã đăng tải");
      database.add(designPatterns);Post statePattern =newPost();
      statePattern.setTitle("State Pattern");
      statePattern.setAuthor("Semi Art");
      statePattern.setStatus("Đã đăng tải");
      database.add(statePattern);Post strategyPattern =newPost();
      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

importstrategypattern.*;importjava.util.ArrayList;importjava.util.List;publicclassPatternDemo{privatestaticList<Post> database;publicstaticvoidmain(String[] args){connectDatabase();// giả định người dùng đánh dấu chọn vài bài viếtList<Post> selectedPosts;// object mô tả thao tác được chọn để áp dụng với các post được đánh dấuAction action =newAction();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(newUnpublish());// 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(newRemove());// 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(newPublish());// 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);}privatestaticvoidconnectDatabase(){...}privatestaticList<Post>selectFirstPost(){return database.stream().filter((post)-> post.getTitle().equalsIgnoreCase("giới thiệu design patterns")).toList();}privatestaticList<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 1Bài viết [StatePattern-SemiArt] đã được gỡ xuống và lưu nháp.
Bài viết [StrategyPattern-SemiArt] đã được gỡ xuống và lưu nháp.==========Thao tác người dùng 2Bài viết [Giới Thiệu DesignPatterns-SemiArt] đã đượ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 3Bài viết [StatePattern-SemiArt] đã được cập nhật và đăng tải.
Bài viết [StrategyPattern-SemiArt] đã được cập nhật và đăng tải.

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ