Pattern trong Java là gì
Trong bài viết này, chúng ta sẽ cùng nhau tìm hiểu mọi thứ về Design Pattern: định nghĩa, bối cảnh sử dụng design pattern Mỗi Design Patter sẽ có code minh họa. Show Design Pattern là gìDesign Pattern là một kỹ thuật trong lập trình hướng đối tượng. Nó cung cấp cho bạn các mẫu thiết kế để giải quyết một vấn đề hay gặp trong thiết kế phần mềm. Các vấn đề mà bạn gặp phải trong quá trình thiết kế phần mềm, có thể bạn đã có giải pháp giải quyết. Tuy nhiên, giải pháp của bạn có thể chưa tối ưu, hoặc nó chưa được trừa tượng hóa để bạn có thể tái sử dụng sau này. Design Pattern giúp bạn giải quyết vấn đề một cách tối ưu nhất, giúp thiết kế phần mềm linh hoạt, dễ dàng thay đổi và bảo trì hơn. Tại sao phải sử dụng Design Pattern?Mỗi người sẽ tự có câu trả lời riêng khi nói đến lý do sử dụng design pattern trong mã nguồn của họ. Tuy nhiên, có thể tóm gọn lại bằng 2 lý do chính:
Phân loại Design PatternTheo quan điểm của các tác giả cuốn sáchDesign Patterns Elements of Reusable Object-Oriented Software, design pattern chủ yếu được dựa theo những nguyên tắc của lập trình hướng đối tượng. Hiện nay, có nhiều loại design pattern và được chia làm 3 dạng chính.
5 design pattern mà bạn nên biếtHiện tại có rất nhiều design patterns, do vậy để bạn có thể nắm vững được hết tất cả là một thử thách khó khăn. Thông thường, trong quá trình làm việc, khi có vấn đề phát sinh, bạn đi tìm giải pháp. Bạn nên tìm xem đã có design pattern nào giải quyết vấn đề của mình rồi hay chưa? Khi đó, bạn sẽ dần dần vừa thực hành vừa tìm hiểu design pattern đó. Tuy nhiên, để có kiến thức nền tảng thì dưới đây là 5 design pattern mà bạn nên tìm hiểu trước. 1. Singleton PatternSingleton pattern có lẽ là pattern phổ biến nhất và cũng dễ dùng nhất. Đúng như tên gọi, nó chỉ cho phép tạo duy nhất một instance của đối tượng ở bất kỳ thời điểm nào. Ví dụ ở thế giới thực đó chính là vị trị tổng thống, mỗi quốc gia chỉ cho phép duy nhất 1 người làm tổng thống mà thôi. Có một vài điều cần lưu ý khi tạo singleton class:
Ví dụ cách triển khai Singleton pattern. class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } public class ClassSingleton { public static void main(String[] args) { System.out.println("--- Singleton Pattern ---"); Singleton single1 = Singleton.getInstance(); Singleton single2 = Singleton.getInstance(); if (single1.equals(single2)) { System.out.println("Unique Instance"); } } }2. Prototype PatternĐể có 1 cái nhìn cơ bản về prototype pattern, bạn xem ví dụ như sau: Giả sử bạn đang thiết kế chương trình vẽ (vẽ các đối tượng hình học cơ bản: hình vuông, hình chữ nhật, ). Tất cả các đối tượng này đều có chung một thiết lập ban đầu (màu sắc, tọa độ,). Thay vì phải lặp đi lặp lại việc tạo các đối tượng, chúng ta có thể:
Đối tượng mà chứa các thiết lập ban đầu được gọi là prototype, và cách thiết kế code kiểu này gọi là prototype pattern. Tóm lại: Về bản chất, prototype pattern là thiết kếcho phép khởi tạo một đối tượng bằng cách sao chép từ một đối tượng khác đã tồn tạithay vì sử dụng toán tử new. Đối tượng mới là một bản sao có thể giống hoàn toàn hoặc được biến đổi một vài thuộc tính so với đối tượng gốc. Đặc biệt, bạn có thể thoải mái thay đổi dữ liệu trên đối tượng bản sao mà không làm ảnh hưởng đến đối tượng gốc. Nếu bạn chỉ copy đối tượng theo cách thông thường thì với ngôn ngữ lập trình như Java chẳng hạn, khi bạn thay đổi dữ liệu ở đối tượng bản sao thì bản gốc cũng bị thay đổi theo. Vì bạn mới chỉ copy địa chỉ tham chiếu mà thôi. Ví dụ cách triển khai Singleton pattern. Tạo 1 abstract class implementing Clonable interface. Shape.javapublic abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }Tạo concrete classes extending của class trên. Rectangle.javapublic class Rectangle extends Shape { public Rectangle(){ type = "Rectangle"; } @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }Square.javapublic class Square extends Shape { public Square(){ type = "Square"; } @Override public void draw() { System.out.println("Inside Square::draw() method."); } }Circle.javapublic class Circle extends Shape { public Circle(){ type = "Circle"; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }Tạo một lớp để có được các lớp cụ thể từ cơ sở dữ liệu và lưu trữ chúng trong một Hashtable. ShapeCache.javaimport java.util.Hashtable; public class ShapeCache { private static HashtablePrototypePatternDemo sử dụng lớp ShapeCache để nhận các bản sao của các hình dạng được lưu giữ trong một Hashtable PrototypePatternDemo.javapublic class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } }3. Builder PatternChúng ta cùng xem xét ví dụ thực tế sau đây. Giả sử bạn đi ăn tối với bạn gái tại một nhà hàng sang chảnh. Nhân viên bồi bàn đưa cho bạn menu với rất nhiều món ăn hấp dẫn, nào là món khai vị, món chính và món tráng miệng. Bạn có thể tùy chọn ăn đủ cả 3 loại món trên,hoặc chỉ 2 trong 3 loại món. Ví dụ, bạn thích ăn luôn món chính rồi tráng miệng sau. Còn người yêu bạn lại chọn ăn từ từ, ăn khai vị cho sang, rồi mới ăn món chính và kết thúc là tráng miệng. Trong thiết kế phần mềm cũng có nhiều tình huống tương tự như thế xảy ra. Bạn có thể xây dựng một đối tượng bằng cách tập hợp từ các tùy chọn có sẵn. Hoặc bạn cần tạo đối tượng theo nhiều cách khác nhau. Đây là lúc Builder pattern được áp dụng. Với bạn nào từng lập trình Android sẽ gặp rất nhiều Builder pattern, điển hình nhất chính là lúc tạo dialog trong Android. Ví dụ cách triển khai Builder Pattern: Những ưu điểm của Builder Pattern là:
4. Proxy PatternTrong đời sống thực, bạn cũng gặp rất nhiều vấn đề liên quan tới proxy. Ví dụ như: Thẻ ATM là một proxy cho tài khoản ngân hàng của bạn. Bất cứ khi nào bạn thực hiện giao dịch bằng thẻ ATM, số tiền tương ứng sẽ bị trừ trong tài khoản ngân hàng. Tương tự trong lập trình phần mềm cũng vậy. Bạn sẽ gặp phải tình huống cần tương tác với đối tượng từ xa (remote). Trong tình huống như vậy, bạn tạo một đối tượng proxy, với mục đích để tương tác với tất cả các nguồn từ bên ngoài. Thay vì bạn phải làm việc trực tiếp với đối tượng ở xa thì bạn làm việc với đối tượng proxy (đã được định nghĩa lại cho phù hợp mục đích sử dụng). Proxy sẽ che giấu sự phức tạp liên quan tới việc giao tiếp với đối tượng thực. Mã nguồn ví dụ: //Image.java public interface Image { void showImage(); } //RealImage.java public class RealImage implements Image { private String url; public RealImage(String url) { this.url = url; System.out.println("Image loaded: " + this.url); } @Override public void showImage() { System.out.println("Image showed: " + this.url); } } //ProxyImage.java public class ProxyImage implements Image { private Image realImage; private String url; public ProxyImage(String url) { this.url = url; System.out.println("Image unloaded: " + this.url); } @Override public void showImage() { if (realImage == null) { realImage = new RealImage(this.url); } else { System.out.println("Image already existed: " + this.url); } realImage.showImage(); } } //Client.java public class Client { public static void main(String[] args) { System.out.println("Init proxy image: "); ProxyImage proxyImage = new ProxyImage("https://vntalking.com/favicon.ico"); System.out.println("---"); System.out.println("Call real service 1st: "); proxyImage.showImage(); System.out.println("---"); System.out.println("Call real service 2nd: "); proxyImage.showImage(); } }5. Observer PatternCó rất nhiều ví dụ trong thực tế cần sử dụng tới Observer pattern. Đơn giản như việc đăng ký theo dõi (subcriber) một kênh Youtube. Bất cứ khi nào kênh Youtube đó có video mới thì bạn sẽ nhận được thông báo. Có hai thành phần chính khi implement một Observer design pattern:
Bạn sẽ hiểu hơn khi đọc đoạn mã ví dụ sau: public class Observer Pattern { static class Notifier { ListKết luậnNhư vậy là chúng ta đã có cái nhìn tổng quan về Design Pattern. Mỗi một design pattern là một cách tiếp cận để giải quyết vấn đề trong một bối cảnh nhất định. Hy vọng các khái niệm này sẽ giúp ích cho các bạn trong công việc của minh. |