Design pattern là gì ?
Design pattern trong Java là các giải pháp được áp dụng cho các vấn đề phổ biến trong lập trình Java. Các mẫu thiết kế này đã được thử nghiệm và kiểm chứng trong quá trình phát triển phần mềm, và được coi là các giải pháp hiệu quả để xử lý các vấn đề tương tự.
Sử dụng các design pattern có thể giúp đơn giản hóa quá trình phát triển phần mềm, giảm thiểu số lượng mã lặp lại, tăng tính tái sử dụng của mã, và làm cho mã trở nên dễ bảo trì hơn.
Một số mẫu thiết kế phổ biến trong Java bao gồm: Singleton, Factory Method, Observer, Decorator, Adapter, Iterator, Strategy, Template Method, Command, và Facade. Mỗi mẫu thiết kế có một mục đích cụ thể và cách sử dụng khác nhau, tùy thuộc vào vấn đề cụ thể mà bạn đang cố gắng giải quyết. Việc hiểu và sử dụng các design pattern trong Java là một kỹ năng quan trọng cho các lập trình viên Java.
Design pattern trong java
Java hỗ trợ nhiều mẫu thiết kế (design pattern) phổ biến, bao gồm:
Singleton Pattern
Sử dụng để đảm bảo rằng chỉ có một thể hiện (instance – Biến toàn cục) của một lớp được tạo ra. Mục đích của việc sử dụng singleton là để đảm bảo rằng sẽ luôn luôn có một và chỉ một thể hiện của lớp được sử dụng trong toàn bộ ứng dụng. Singleton cũng có thể được sử dụng để truy cập các thành phần chung trong một ứng dụng, ví dụ như các cấu hình hệ thống hoặc các bộ quản lý đối tượng (Object Managers).
Ví dụ về biến instance (Biến toàn cục) trong java:
package net.sharecs.bienvadulieu;
public class Sinhvien {
// biến instance "ten" kiểu String, có giá trị mặc định là null
// biến instance "ten" chỉ có một bạn không được khai báo tiếp các biến có trùng tên ví dụ như: private String ten;..
public String ten;
// biến instance "tuoi" kiểu Integer, có giá trị mặc định là 0
private int tuoi;
// sử dụng biến ten trong một constructor
public Sinhvien(String ten) {
this.ten = ten;
}
// sử dụng biến tuoi trong phương thức setTuoi
public void setTuoi(int tuoi) {
this.tuoi = tuoi;
}
public void showStudent() {
System.out.println("Ten : " + ten);
System.out.println("Tuoi : " + tuoi);
}
public static void main(String args[]) {
Sinhvien sv = new Sinhvien("Nguyen Van A");
sv.setTuoi(21);
sv.showStudent();
}
}
Lưu ý:
- Biến instance được khai báo trong một lớp ( class ), bên ngoài các phương thức ( method ), constructor và các block.
- Biến instance được lưu trong bộ nhớ heap
- Biến instance được tạo khi một đối tượng được tạo bằng việc sử dụng từ khóa “new” và sẽ bị phá hủy khi đối tượng bị hủy.
- Biến instance có thể được sử dụng bởi các phương thức, constructor, block,… Nhưng nó phải được sử dụng thông qua một đối tượng cụ thể.
- Chung ta có thể dử dụng “access modifier” khi khai báo biến instance, mặc định sẽ là default.
- Biến instance sẽ có giá trị mặc định phụ thuộc vào kiểu dữ liệu. Ví dụ String là null, int và bye là 0 … Nên bạn sẽ không cần khởi tạo dữ liệu mặc định.
- Trong một class bạn khai báo biến instance thì bạn có thể gọi trực tiếp bằng tên khi sử dụng ở khắp nơi bên trong class đó.
Factory Pattern
Factory Pattern: Cho phép tạo ra các đối tượng của các lớp con một cách linh hoạt, mà không cần phải chỉ định chính xác lớp cụ thể. Hay giải thích một cách dễ hiểu hơn thì Pattern này được sinh ra nhằm mục đích khởi tạo đối tượng mà bản thân muốn che giấu class nào được khởi tạo.
Về cơ bản thì ta sẽ định nghĩa một interface hoặc Abstract class , các class con sẽ implements nó. Tiếp đến mình sẽ tạo một class được xem là FactoryClass, bên trong FactoryClass này mình sẽ có một phương thức giúp chúng ta khởi tạo các Object chúng ta cần.
Mình lấy ví dụ để mình có thể hiểu rõ hơn nha:
Như mình viết trên thì mính sẽ tạo một interface Laptop:
public interface Laptop {
public void showInfo();
}
Tiếp đến mình muốn có một laptop của một vài hãng như Dell, Apple, HP,.. Nên mình sẽ khai báo các class DellLaptop, AppleLaptop, HpLaptop:
public class DellLaptop implements Laptop {
@Override
public void showInfo() {
System.out.printf("Đây là Laptop Dell");
}
}
public class AppleLaptop implements Laptop {
@Override
public void showInfo() {
System.out.printf("Đây là Laptop Apple");
}
}
public class HpLaptop implements Laptop {
@Override
public void showInfo() {
System.out.printf("Đây là Laptop Hp");
}
}
public enum LaptopType {
DELL, HP, APPLE
}
Sau khi mình có được các class Laptop trên thì sẽ tạo FactoryClass có tên là LaptopFactory.
public class LaptopFactory {
public Laptop getLaptop(LaptopType laptopType) {
Laptop laptopCreated = null;
switch (laptopType) {
case DELL:
laptopCreated = new DellLaptop();
break;
case APPLE:
laptopCreated = new AppleLaptop();
break;
case HP:
laptopCreated = new HpLaptop();
break;
}
return laptopCreated;
}
}
Bây giờ mình sẽ chạy demo:
public class RunDemo {
public static void main(String[] args) {
LaptopFactory laptopFactory = new LaptopFactory();
Laptop laptop = laptopFactory.getLaptop(LaptopType.HP);
laptop.showInfo();
}
}
public class RunDemo {
public static void main(String[] args) {
LaptopFactory laptopFactory = new LaptopFactory();
Laptop laptop = laptopFactory.getLaptop(LaptopType.HP);
laptop.showInfo();
}
}
Và kết quả có được là:
Đây là Laptop Hp
Observer Pattern
Observer Pattern: Cho phép các đối tượng đăng ký để theo dõi sự kiện xảy ra trong đối tượng khác và được thông báo khi sự kiện đó xảy ra. Dễ hiểu hơn nữa nó là dạng pattern mà khi 1 object có bất kỳ thay đổi trạng thái nào, nó có thể thông báo cho tất cả các object khác đăng ký nhận sự thay đổi từ nó.
Decorator Pattern
Decorator Pattern: Cho phép các đối tượng được bọc bởi các đối tượng khác để mở rộng chức năng của chúng mà không thay đổi giao diện của chúng.
Adapter Pattern
Adapter Pattern: Chuyển đổi giao diện của một lớp thành giao diện khác, để các đối tượng có thể tương tác với nhau mà không cần phải biết chi tiết về nhau.
Iterator Pattern
Iterator Pattern: Cung cấp cách truy cập tuần tự đến các phần tử của một tập hợp mà không tiết lộ cách thức hoạt động của nó.
Strategy Pattern
Strategy Pattern: Cho phép thay đổi hành vi của một đối tượng bằng cách chọn một trong nhiều thuật toán khác nhau trong thời gian chạy.
Template Method Pattern
Template Method Pattern: Định nghĩa một khuôn mẫu để thực hiện một thuật toán và cho phép các lớp con triển khai lại các bước cụ thể của thuật toán đó.
Command Pattern
Command Pattern: Đóng gói yêu cầu dưới dạng một đối tượng và cho phép thực hiện yêu cầu đó ở một thời điểm khác nhau.
Facade Pattern
Facade Pattern: Cung cấp một giao diện đơn giản cho một tập hợp lớp phức tạp để dễ dàng sử dụng.