Design pattern trong java (Bài 8)

Design pattern trong java hay còn gọi là mẫu thiết kế. Design pattern trong java là giải pháp tốt để giải quyết các vấn đề hoặc nhiệm vụ cụ thể. Đến đây, các bạn có thể tự hỏi vấn đề cụ thể đó là gì? Chúng tôi sẽ giải thích thông qua một ví dụ.

Design pattern trong java – Ví dụ

Giả sử bạn muốn tạo một lớp và sử dụng lớp này để tạo một đối tượng mà đối tượng này được sử dụng bởi tất cả các lớp khác. Giải pháp tốt nhất trong trường hợp này là sử dụng Singleton design pattern.

Như vậy design pattern là độc lập với ngôn ngữ lập trình để giải quyết các vấn đề phổ biến trong thiết kế hướng đối tượng. Nghĩa là một design pattern là một ý tưởng, không phải là một cài đặt cụ thể.

Bằng cách sử dụng design pattern, chúng ta sẽ tạo ra những đoạn code linh hoạt hơn, có khả năng tái sử dụng hơn và dễ bảo trì nâng cấp hơn.

Design pattern trong java – Các loại design pattern (Types of Design Patterns)

STT Design pattern và Miêu tả
1 Creational Patterns
Nhóm này cung cấp phương pháp tạo ra các đối tượng một cách linh hoạt hơn. Nghĩa là quyết định đối tượng nào được tạo ra tuỳ thuộc vào trường hợp sử dụng nhất định.
2 Structural Patterns
Nhóm này liên quan đến sự kết hợp giữa các đối tượng với nhau
3 Behavioral Patterns
Mẫu thiết kế này trình bày phương pháp thiết kế liên quan đến hành vi của các đối tượng.
4 J2EE Patterns
Nhóm này cung cấp phương pháp thiết kế chương trình theo mô hình nhiều tầng (multiple tier)

Design pattern trong java – Singleton pattern

Singleton design pattern là một trong những mẫu thiết kế đơn giản nhất và thuộc nhóm Creational Patterns. Sau đây là ví dụ cài đặt theo Singleton

design pattern trong java 1

Ví dụ sau đây được thực hiện trên cơ sở dữ liệu EMPDB sử dụng SQL Server. Trong EMPDB có bảng ACCOUNTS. Câu lệnh tạo bảng này như sau

CREATE TABLE ACCOUNTS (
  USERNAME VARCHAR(20) PRIMARY KEY
  ,PASS VARCHAR(20)
)

Cài đặt (Implementation)

Bước 1: Tạo lớp Singleton (JDBCSingleton.java), lưu ý thay đổi phần in đậm màu đỏ cho phù hợp.

package designpatterns.singleton;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 *
 * @author giasutinhoc.vn
 */
public class JDBCSingleton { 
 private static JDBCSingleton jdbc;
 private JDBCSingleton() {

 }

 public static JDBCSingleton getInstance() {
  if (jdbc == null) {
    jdbc = new JDBCSingleton();
  }
  return jdbc;
 }

 private static Connection getConnection() throws Exception {
   return DriverManager.getConnection("jdbc:sqlserver://localhost;databaseName=EMPDB;user=sa;password=sa");
 }

 // Thêm dữ liệu vào db 
 public int create(String username, String pass) throws SQLException {
   Connection c = null;
   PreparedStatement ps = null;
   int cnt = 0;

   try {
    c = this.getConnection();
    ps = c.prepareStatement("insert into accounts(username,pass) values(?,?)");
    ps.setString(1, username);
    ps.setString(2, pass);
    cnt = ps.executeUpdate();

   } catch (Exception e) {
     System.out.print(e.toString());
   } finally {
     if (ps != null) {
       ps.close();
     }
     if (c != null) {
       c.close();
     }
   }
   return cnt;
 }

 //Hiển dữ liệu
 public void display(String id) throws SQLException {
   Connection con = null;
   PreparedStatement ps = null;
   ResultSet rs = null;
   int cnt = 0;
   try {
     con = this.getConnection();
     ps = con.prepareStatement("select * from accounts where username = ?");
     ps.setString(1, id);
     rs = ps.executeQuery();
 
     while (rs.next()) {
       System.out.println("Ten " + rs.getString("username") + " va mat khau " + rs.getString("pass"));
       cnt++;
     }
 
     if (cnt == 0) {
       System.out.println("Khong co tai khoan nao ton tai");
     }
   } catch (Exception e) {
     System.out.println(e);
   } finally {
     if (rs != null) {
      rs.close();
     }
     if (ps != null) {
      ps.close();
     }
     if (con != null) {
      con.close();
     }
   }
  }
}

Bước 2: Lấy đối tượng từ lớp singleton (JDBCSingletonExample.java)

package designpatterns.singleton;

import java.util.Scanner;

/**
 *
 * @author giasutinhoc.vn
 */
public class JDBCSingletonExample {

 public static void main(String[] args) throws Exception {
 //JDBCSingleton object = new JDBCSingleton();
  JDBCSingleton jdbc = JDBCSingleton.getInstance();

  Scanner s = new Scanner(System.in);
 
  int count = 1;
  int choice;

  do {
   System.out.println(" 1. Create account");
   System.out.println(" 2. Display account");
   System.out.println(" 3. Exit");

   System.out.print("Please enter the choice: ");
   choice = s.nextInt();

   //clear buffer
   s.nextLine();

   switch (choice) {
    case 1:
     System.out.print("Nhap ten : ");
     String username = s.nextLine();
     System.out.print("Nhap mat khau : ");
     String password = s.nextLine();

     try {
      int i = jdbc.create(username, password);
      if (i > 0) {
        System.out.println("Them thanh cong");
      } else {
        System.out.println("Them that bai ");
      }
     } catch (Exception e) {
       System.out.println(e);
     }
     break;
   case 2:
     System.out.print("Nhap ten : ");
     username = s.nextLine();
     try {
      jdbc.display(username);
     } catch (Exception e) {
       System.out.println(e);
     }
     break;
   }
  } while (choice != 3);
 }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

design pattern trong java 2

Design pattern trong java – Adapter pattern

Adapter Pattern hoạt động như một cầu nối giữa hai giao diện khác nhau (không tương thích) và thuộc nhóm Structural Patterns. Mô hình này kết hợp khả năng của hai giao diện độc lập.

Cài đặt Adapter Pattern

design pattern trong java 3

Bước 1: Tạo interface tên MediaPlayer và AdvMediaPlayer

/**
 *
 * @author giasutinhoc.vn
 */
public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
/**
 *
 * @author giasutinhoc.vn
 */
public interface AdvancedMediaPlayer {	
   public void playMp4(String fileName);
}

Bước 2: Tạo lớp Mp4Player cài đặt giao diện AdvMediaPlayer

/**
 *
 * @author giasutinhoc.vn
 */
public class Mp4Player implements AdvancedMediaPlayer{ 
   @Override
   public void playMp4(String fileName) {
      System.out.println("Dang phat mp4: "+ fileName);		
   }
}

Bước 3: Tạo lớp MediaAdapter cài đặt giao diện MediaPlayer

/**
 *
 * @author giasutinhoc.vn
 */
public class MediaAdapter implements MediaPlayer {

   AdvancedMediaPlayer advancedMusicPlayer;

   public MediaAdapter(String audioType){
   
     if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }	
   }

   @Override
   public void play(String audioType, String fileName) {
   
     if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

Bước 4: Tạo lớp AudioPlayer cài đặt giao diện MediaPlayer

/**
 *
 * @author giasutinhoc.vn
 */
public class AudioPlayer implements MediaPlayer {
 MediaAdapter mediaAdapter; 

 @Override
 public void play(String audioType, String fileName) { 
  if(audioType.equalsIgnoreCase("mp3")){
    System.out.println("Dang phat mp3: " + fileName); 
  } else if(audioType.equalsIgnoreCase("mp4")){    
    mediaAdapter = new MediaAdapter(audioType);
    mediaAdapter.play(audioType, fileName);
  } else{
    System.out.println("Khong hop le. " + audioType + " dinh dang khong duoc ho tro");
  }
 } 
}

Bước 5: Sử dụng AudioPlayer để phát nhiều loại audio khác nhau

/**
 *
 * @author giasutinhoc.vn
 */
public class AdapterPatternExample {
   public static void main(String[] args) {
      AudioPlayer ap= new AudioPlayer();

      ap.play("mp3", "yesterday.mp3");
      ap.play("mp4", "jump.mp4");      
   }
}

Khi chạy chương trình trên, chúng ta nhận được kết quả sau

Dang phat mp3: yesterday.mp3
Dang phat mp4: jump.mp4

Design pattern trong java – Chain of Responsibility Pattern

Trong Chain of Responsibility Pattern, sender gửi một yêu cầu đến chuỗi đối tượng (chain of objects). Yêu cầu này có thể được xử lý bởi bất kỳ đối tượng nào trong chuỗi đối tượng. Chain of Responsibility Pattern thuộc nhóm Behavioral Patterns.

Cài đặt Chain of Responsibility Pattern

Chúng ta tạo môt lớp trừu tượng AbstractConsole có thuộc tính level. Sau đó, chúng ta tạo 2 loại logger kế thừa lớp trừu tượng AbstractConsole. Mỗi khi có yêu cầu hiển thị thông báo, hệ thống sẽ dựa vào level để in thông báo phù hợp (hành vi), ngược lại hệ thống sẽ chuyển yêu cầu cho logger kế tiếp.

design pattern trong java 4

Bước 1: Tạo lớp trừu tượng AbstractConsole

/**
 *
 * @author giasutinhoc.vn
 */
public abstract class AbstractConsole {
   public static int INFO = 1;
   public static int WARNING = 2;  

   protected int level;

   protected AbstractConsole nextLogger;

   public void setNextLogger(AbstractConsole nextLogger){
      this.nextLogger = nextLogger;
   }

   public void printMessage(int level, String message){
      if(this.level <= level){
         write(message);
      }
      if(nextLogger !=null){
         nextLogger.printMessage(level, message);
      }
   }

   abstract protected void write(String message);
	
}

Bước 2: Tạo lơp InfoLogger kế thừa lớp trừu tượng AbstractConsole

/**
 *
 * @author giasutinhoc.vn
 */
public class InfoLogger extends AbstractConsole {

   //Constructor
   public InfoLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String msg) {		
      System.out.println("Info: " + mgs);
   }
}

Bước 3: Tạo lớp WarningLogger kế thừa lớp trừu tượng AbstractConsole

public class WarningLogger extends AbstractConsole {

   public WarningLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String msg) {		
      System.out.println("Warning: " + msg);
   }
}

Bước 4: Tạo lớp ChainPatternExample

/**
 *
 * @author giasutinhoc.vn
 */
public class ChainPatternExample {
	
   private static AbstractConsole getChainOfLoggers(){

      AbstractConsole info = new InfoLogger(AbstractConsole.INFO);
      AbstractConsole warning = new WarningLogger(AbstractConsole.WARNING);      

      info.setNextLogger(warning);

      return info;	
   }

   public static void main(String[] args) {
      AbstractConsole ac= getChainOfLoggers();

      ac.printMessage(AbstractConsole.INFO, "Day la info.");
      ac.printMessage(AbstractConsole.WARNING, "Day la warning.");      
   }
}

Design pattern trong java – Data Access Object Pattern

Data Access Object Pattern hay DAO Pattern được sử dụng để tách thao tác xử lý dữ liệu riêng biệt với tầng nghiệp vụ trong khi xây dựng chương trình. DAO Pattern thuộc nhóm J2EE Patterns

Cài đặt DAO Pattern trong Java

design pattern trong java 6

Data Access Object Interface: Định nghĩa những thao tác trong hệ thống

Data Access Object Class: Cài đặt interface và thực hiện các thao tác với dữ liệu từ cơ sở dữ liệu, JSON/XML, …

Model Object hoặc Value Object: Đối tượng chứa các phương thức get/set và sử dụng để đóng gói dữ liệu.

Bước 1: Tạo lớp Employee (Model Object hoặc Value Object)

/**
 *
 * @author giasutinhoc.vn
 */
public class Employee {
   private int id;
   private String name;

   Employee(int id, String name){
      this.id= id;
      this.name = name;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

Bước 2: Tạo giao diện EmployeeDao (Data Access Object Interface)

/**
 *
 * @author giasutinhoc.vn
 */
import java.util.ArrayList;

public interface EmployeeDao {
   public ArrayList<Employee> getAllEmployees();
   public Employee getEmployee(int id);
   public void updateEmployee(Employee emp);
   public void deleteEmployee(Employee emp);
}

Bước 3: Tạo lớp EmployeeDaoImpl cài đặt EmployeeDao (Data Access Object Class)

import java.util.ArrayList;

/**
 *
 * @author giasutinhoc.vn
 */
public class EmployeeDaoImpl implements EmployeeDao {
	
   ArrayList<Employee> alEmp;

   public EmployeeDaoImpl(){
      alEmp = new ArrayList<Employee>();
      Employee e1 = new Employee(1, "Xuân");
      Employee e2 = new Employee(2, "Hạ");
      alEmp.add(e1);
      alEmp.add(e2);		
   }

   @Override
   public void deleteEmployee(Employee e) {
      alEmp.remove(e.getId());
      System.out.println("Nhan vien co ID " + e.getId() + "da bi xoa");
   }

   @Override
   public ArrayList<Employee> getAllEmployees() {
      return alEmp;
   }

   @Override
   public Employee getEmployee(int id) {
      return alEmp.get(id);
   }

   @Override
   public void updateEmployee(Employee e) {
      alEmp.get(e.getId()).setName(e.getName());
      System.out.println("Nhan vien co ID " + e.getId() + " da duoc cap nhat");
   }
}

Bước 4: Tạo lớp DaoPatternExample

/**
 *
 * @author giasutinhoc.vn
 */
public class DaoPatternExample {
   public static void main(String[] args) {
      EmployeeDao empDao = new EmployeeDaoImpl();

      //Hiển thị tất cả
      for (Employee e : empDao.getAllEmployees()) {
         System.out.println("Nhan vien: [ID : " + e.getId() + ", Ten : " + e.getName() + "]");
      }

      //Cập nhật
      Employee e = empDao.getAllEmployees().get(0);
      e.setName("Nguyễn Văn Xuân");
      empDao.updateEmployee(e);

      //Hiển thị
      e = empDao.getEmployee(0);
      System.out.println("Nhan vien: [ID : " + e.getId() + ", Ten : " + e.getName() + "]");
   }
}

Khi chạy chương trình trên, chúng ta thu được kết quả sau

design pattern trong java 5

Xem thêm hướng dẫn xây dựng mô hình mvc

Tổng kết bài design pattern trong java

  • Design pattern với Creational
  • Design pattern với Structural 
  • Design pattern với Behavioral 
  • Design pattern với J2EE

Trả lời