Trong lập trình phần mềm, "Design Patterns" hay "Mẫu thiết kế" là những giải pháp tiêu chuẩn để giải quyết các vấn đề thường gặp trong thiết kế phần mềm. Các mẫu thiết kế không phải là mã hoàn chỉnh mà là một mô tả hoặc khuôn mẫu cho cách giải quyết một vấn đề mà bạn có thể tùy chỉnh cho ứng dụng của mình. Trong Java, các mẫu thiết kế được chia thành ba loại chính: Creational, Structural và Behavioral. Dưới đây là một số mẫu thiết kế phổ biến trong mỗi loại và cách chúng được sử dụng trong Java.
Creational Patterns
1. Singleton Pattern
Singleton Pattern đảm bảo rằng một lớp chỉ có một thể hiện duy nhất, và cung cấp một điểm truy cập toàn cầu đến thể hiện đó. Mẫu này thường được sử dụng cho các tác vụ như quản lý cấu hình, quản lý kết nối cơ sở dữ liệu.
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2. Factory Method Pattern
Factory Method Pattern cung cấp một giao diện để tạo đối tượng trong một lớp cha, nhưng cho phép các lớp con thay đổi loại đối tượng sẽ được tạo.
java
public abstract class Dialog {
public void renderWindow() {
Button okButton = createButton();
okButton.render();
}
public abstract Button createButton();
}
public class WindowsDialog extends Dialog {
@Override
public Button createButton() {
return new WindowsButton();
}
}
public class WindowsButton implements Button {
public void render() {
System.out.println("Render a Windows button");
}
}
Structural Patterns
1. Adapter Pattern
Adapter Pattern cho phép các đối tượng với các giao diện không tương thích làm việc cùng nhau. Mẫu này thường được sử dụng để hệ thống mới có thể làm việc với các lớp cũ.
java
public interface MediaPlayer {
void play(String audioType, String fileName);
}
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
} else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
2. Proxy Pattern
Proxy Pattern cung cấp một đại diện hoặc người đứng thay thế cho một đối tượng khác để kiểm soát quyền truy cập vào đối tượng này.
java
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
Behavioral Patterns
1. Observer Pattern
Observer Pattern được sử dụng khi có một-tới-nhiều mối quan hệ phụ thuộc giữa các đối tượng sao cho khi một đối tượng thay đổi trạng thái, tất cả các phụ thuộc của nó đều được thông báo và cập nhật tự động.
java
public interface Observer {
void update();
}
public interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyUpdate();
}
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void notifyUpdate() {
for(Observer o: observers) {
o.update();
}
}
}
public class ConcreteObserver implements Observer {
public void update() {
System.out.println("Observer updated");
}
}
Các mẫu thiết kế này chỉ là một phần của kho tàng kiến thức lập trình hướng đối tượng trong Java, giúp các nhà phát triển giải quyết các vấn đề phức tạp một cách hiệu quả và tái sử dụng mã nguồn một cách hiệu quả.