Những Design pattern thú vị trong Java | Part 2
Chào mừng các tín đồ của Design Pattern đã quay trở lại với chủ đề này trong Part 2. (clap) Và với chủ đề ngày hôm nay chúng ta sẽ tiếp tục đi đến Design Pattern thú vị tiếp theo nhé. Abstract Factory (Creational Design Patterns) Composite Pattern (Structural Design Patterns) Observer ...
Chào mừng các tín đồ của Design Pattern đã quay trở lại với chủ đề này trong Part 2. (clap) Và với chủ đề ngày hôm nay chúng ta sẽ tiếp tục đi đến Design Pattern thú vị tiếp theo nhé.
- Abstract Factory (Creational Design Patterns)
- Composite Pattern (Structural Design Patterns)
- Observer Pattern (Behavioral Design Patterns)
Abstract Factory
Đây là mẫu thiết kế được mở rộng từ Factory pattern, chúng ta hình dung Abstract factory một nhà máy lớn chứa nhiều nhà máy nhỏ, trong các nhà máy đó có những xưởng sản xuất, các xưởng đó tạo ra những sản phẩm khác nhau. Mục tiêu:
- Tạo ra đối tượng mà không cần biết chính xác kiểu dữ liệu.
- Giúp mã nguồn của bạn trở nên dễ dàng bảo trì nếu có sự thay đổi. Để dễ hiểu hơn chúng ta cùng nhau bóc tách vấn đề qua một ví dụ dưới đây nhé !
- AbstractFactory: là một abstract class chứa phương thức create abstract products
- ConcreteFactory: thực hiện các hoạt động để tạo ra concrete products
- AbstractProduct: khai báo một giao diện của từng loại product
- Product: implements AbstractProduct và định nghĩa việc trả về 1 product riêng biệt
- Client: sử dụng AbstractFactory và AbstractProduct class.
Triển khai:
AbstractFactory.java
abstract class AbstractFactory{ abstract AbstractProductA createProductA(); abstract AbstractProductB createProductB(); }
ConcreteFactory1.java
class ConcreteFactory1 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA1("ProductA1"); } AbstractProductB createProductB(){ return new ProductB1("ProductB1"); } }
ConcreteFactory2.java
class ConcreteFactory2 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA2("ProductA2"); } AbstractProductB createProductB(){ return new ProductB2("ProductB2"); } }
AbstractProductA.java
abstract class AbstractProductA{ public abstract void operationA1(); public abstract void operationA2(); }
AbstractProductB.java
abstract class AbstractProductB{ public abstract void operationB1(); public abstract void operationB2(); }
ProductA1.java
class ProductA1 extends AbstractProductA{ ProductA1(String arg){ System.out.println("Hello A1 "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; }
ProductA2.java
class ProductA2 extends AbstractProductA{ ProductA1(String arg){ System.out.println("Hello A2 "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; }
ProductB1.java
class ProductB1 extends AbstractProductB{ ProductB1(String arg){ System.out.println("Hello B1 "+arg); } // Implement the code here }
ProductB2.java
class ProductB2 extends AbstractProductB{ ProductB2(String arg){ System.out.println("Hello B2"+arg); } // Implement the code here }
Client.java
public class Client{ public static void main(String args[]){ AbstractFactory pf=FactoryMaker.getFactory("a"); AbstractProductA product=pf.createProductA(); //more function calls on product } }
Composite Pattern
Tổ chức các đối tượng theo cấu trúc phân cấp dạng cây. Tất cả các đối tượng trong cấu trúc được thao tác theo một cách thuần nhất như nhau.
Mục tiêu:
- Tạo quan hệ thứ bậc bao gộp giữa các đối tượng.
- Client có thể xem đối tượng bao gộp và bị bao gộp như nhau -> khả năng tổng quát hoá trong code của client -> dễ phát triển, nâng cấp, bảo trì. Cài đặt:
- Base Component: là một interface hoặc abstract class cho tất cả các object kế thừa và có những method dùng chung của objects đó.
- Leaf: xác định từng hành vi của object khi implement lại BaseComponent , nhưng không tham chiếu tới thành phần khác.
- Composite: chứa toàn bộ leaf objects và implement BaseComponent Chúng ta cùng nhau tìm hiểu qua một ví dụ đơn giản để hiểu hơn về Composite pattern nhé. Ví dụ: chúng ta có 1 list Objects là Circle, Lines, Triangle . Khi muốn tô màu cho chúng ( màu ĐỎ chẳng hạn ) thì tất cả list objects sẽ được vẽ bằng màu đỏ. Mình sẽ cùng nhìn vào sơ đồ phía dưới nhé :
Shape.java
public interface Shape { public void draw(String fillColor); }
Circle.java
public class Circle implements Shape { @Override public void draw(String fillColor) { System.out.println("Drawing Circle with color "+fillColor); } }
Triangle.java
public class Triangle implements Shape { @Override public void draw(String fillColor) { System.out.println("Drawing Triangle with color "+fillColor); } }
Line.java
public class Line implements Shape { @Override public void draw(String fillColor) { System.out.println("Drawing Line with color "+fillColor); } }
Drawing.java
public class Drawing implements Shape{ //collection of Shapes private List<Shape> shapes = new ArrayList<Shape>(); @Override public void draw(String fillColor) { for(Shape sh : shapes) { sh.draw(fillColor); } } //adding shape to drawing public void add(Shape s){ this.shapes.add(s); } //removing shape from drawing public void remove(Shape s){ shapes.remove(s); } //removing all the shapes public void clear(){ System.out.println("Clearing all the shapes from drawing"); this.shapes.clear(); } }
TestCompositePattern.java
public class TestCompositePattern { public static void main(String[] args) { Shape line = new Line(); Shape tri = new Triangle(); Shape cir = new Circle(); Drawing drawing = new Drawing(); drawing.add(line); drawing.add(tri); drawing.add(cir); drawing.draw("Red"); drawing.clear(); drawing.add(line); drawing.add(cir); drawing.draw("Green"); } }
Observer Pattern
Observer cho phép các đối tượng có thể lắng nghe và phản ứng khi có thông báo từ một đối tượng khác. Tức là khi một đối tượng gửi một thông báo, các đối tượng lắng nghe nó có thể phản ứng lại với thông báo đó.
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. Mục tiêu:
Khi bạn muốn các đối tượng liên lạc với nhau. Khi đối tượng này gửi 1 thông điệp thì các đối tượng đăng ký lắng nghe thông điệp sẽ phản ứng lại với thông điệp đó. Đối tượng gửi thông điệp sẽ không cần biết nó sẽ gửi cho ai và đối tượng nhận thông điệp sẽ không cần biết ai gửi thông điệp đó.
Một ví dụ : Chúng ta tạo ra một topic và observer có thể đăng kí lắng nghe topic này. Khi có bất kì tin nhắn mới nào ( một comment mới, like or share .. ) thì những registers sẽ nhận được thông báo và có thể thao tác lại với những tin nhắn đó. Hình phía dưới mô tả tổng thể bài toán chúng ta muốn triển khai.
Subject.java ( interface chứa những phương thức nhằm liên lạc với bất kỳ subject nào)
public interface Subject { //methods to register and unregister observers public void register(Observer obj); public void unregister(Observer obj); //method to notify observers of change public void notifyObservers(); //method to get updates from subject public Object getUpdate(Observer obj); }
Observer.java ( chứa method cập nhật trạng thái và truyền subject khi lắng nghe sự thay đổi)
public interface Observer { //method to update the observer, used by subject public void update(); //attach with subject to observe public void setSubject(Subject sub); }
Tiếp theo, chúng ta tạo ra MyTopic.java có chức năng post message và implement lại Subject interface. MyTopic.java
public class MyTopic implements Subject { private List<Observer> observers; private String message; private boolean changed; private final Object MUTEX= new Object(); public MyTopic(){ this.observers=new ArrayList<>(); } @Override public void register(Observer obj) { if(obj == null) throw new NullPointerException("Null Observer"); synchronized (MUTEX) { if(!observers.contains(obj)) observers.add(obj); } } @Override public void unregister(Observer obj) { synchronized (MUTEX) { observers.remove(obj); } } @Override public void notifyObservers() { List<Observer> observersLocal = null; //synchronization is used to make sure any observer registered after message is received is not notified synchronized (MUTEX) { if (!changed) return; observersLocal = new ArrayList<>(this.observers); this.changed=false; } for (Observer obj : observersLocal) { obj.update(); } } @Override public Object getUpdate(Observer obj) { return this.message; } //method to post message to the topic public void postMessage(String msg){ System.out.println("Message Posted to Topic:"+msg); this.message=msg; this.changed=true; notifyObservers(); } }
Một class có chức năng theo dõi sự thay đổi từ MyTopic.java MyTopicSubscriber.java
public class MyTopicSubscriber implements Observer { private String name; private Subject topic; public MyTopicSubscriber(String nm){ this.name=nm; } @Override public void update() { String msg = (String) topic.getUpdate(this); if(msg == null){ System.out.println(name+":: No new message"); }else System.out.println(name+":: Consuming message::"+msg); } @Override public void setSubject(Subject sub) { this.topic=sub; } }
Chương trình chạy để kiểm tra kết quả đã tiến hành ở trên: ObserverPatternTest.java
public class ObserverPatternTest { public static void main(String[] args) { //create subject MyTopic topic = new MyTopic(); //create observers Observer obj1 = new MyTopicSubscriber("Obj1"); Observer obj2 = new MyTopicSubscriber("Obj2"); Observer obj3 = new MyTopicSubscriber("Obj3"); //register observers to the subject topic.register(obj1); topic.register(obj2); topic.register(obj3); //attach observer to subject obj1.setSubject(topic); obj2.setSubject(topic); obj3.setSubject(topic); //check if any update is available obj1.update(); //now send message to subject topic.postMessage("New Message"); } }
Kết quả:
Obj1:: No new message Message Posted to Topic:New Message Obj1:: Consuming message::New Message Obj2:: Consuming message::New Message Obj3:: Consuming message::New Message
Tổng kết
Bài viết trên đây chia sẻ thêm về 3 design pattern Abstract Factory, Composite Pattern, Observer Pattern được ứng dụng nhiều trong quá trình chúng ta phát triển một project, các chức năng và ví dụ chi tiết. Mong rằng sẽ là nguồn tài liệu cung cấp kiến thức bổ ích hơn cho các bạn đang muốn hiểu thêm về Design pattern.