+3

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é.

  1. Abstract Factory (Creational Design Patterns)
  2. Composite Pattern (Structural Design Patterns)
  3. 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é !
  1. AbstractFactory: là một abstract class chứa phương thức create abstract products
  2. ConcreteFactory: thực hiện các hoạt động để tạo ra concrete products
  3. AbstractProduct: khai báo một giao diện của từng loại product
  4. Product: implements AbstractProduct và định nghĩa việc trả về 1 product riêng biệt
  5. 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.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí