Phần 1 trước, Cafedev đã giới thiệu khá chi tiết về observer pattern, Bài này chúng ta sẽ tiến hành thực hành nó với code cụ thể. Ace có thể tham khảo các bài khác tại series Design Pattern tại đây.

Giả sử chúng ta đang xây dựng một ứng dụng thông báo cricket cho người xem về các thông tin như điểm số hiện tại, tỷ lệ chạy, v.v. Giả sử chúng ta đã tạo hai phần tử hiển thị là CurrentScoreDisplay và AverageScoreDisplay. CricketData có tất cả dữ liệu (chạy, điểm, v.v.) và bất cứ khi nào dữ liệu thay đổi, các phần tử hiển thị sẽ được thông báo với dữ liệu mới và chúng hiển thị dữ liệu mới nhất tương ứng

Áp dụng Observer pattern cho vấn đề trên:

Hãy để chúng ta xem cách chúng ta có thể cải thiện thiết kế ứng dụng của mình bằng cách sử dụng Observer pattern. Nếu chúng ta quan sát luồng dữ liệu, chúng ta có thể dễ dàng thấy rằng CricketData và các phần tử hiển thị tuân theo mối quan hệ chủ thể(subject)-người quan sát(observers).

Sơ đồ lớp mới:

Triển khai bằng code Java:

// Java program to demonstrate working of 
// onserver pattern 
import java.util.ArrayList; 
import java.util.Iterator; 

// Implemented by Cricket data to communicate 
// with observers 
interface Subject 
{ 
	public void registerObserver(Observer o); 
	public void unregisterObserver(Observer o); 
	public void notifyObservers(); 
} 

class CricketData implements Subject 
{ 
	int runs; 
	int wickets; 
	float overs; 
	ArrayList<Observer> observerList; 

	public CricketData() { 
		observerList = new ArrayList<Observer>(); 
	} 

	@Override
	public void registerObserver(Observer o) { 
		observerList.add(o); 
	} 

	@Override
	public void unregisterObserver(Observer o) { 
		observerList.remove(observerList.indexOf(o)); 
	} 

	@Override
	public void notifyObservers() 
	{ 
		for (Iterator<Observer> it = 
			observerList.iterator(); it.hasNext();) 
		{ 
			Observer o = it.next(); 
			o.update(runs,wickets,overs); 
		} 
	} 

	// get latest runs from stadium 
	private int getLatestRuns() 
	{ 
		// return 90 for simplicity 
		return 90; 
	} 

	// get latest wickets from stadium 
	private int getLatestWickets() 
	{ 
		// return 2 for simplicity 
		return 2; 
	} 

	// get latest overs from stadium 
	private float getLatestOvers() 
	{ 
		// return 90 for simplicity 
		return (float)10.2; 
	} 

	// This method is used update displays 
	// when data changes 
	public void dataChanged() 
	{ 
		//get latest data 
		runs = getLatestRuns(); 
		wickets = getLatestWickets(); 
		overs = getLatestOvers(); 

		notifyObservers(); 
	} 
} 

// This interface is implemented by all those 
// classes that are to be updated whenever there 
// is an update from CricketData 
interface Observer 
{ 
	public void update(int runs, int wickets, 
					float overs); 
} 

class AverageScoreDisplay implements Observer 
{ 
	private float runRate; 
	private int predictedScore; 

	public void update(int runs, int wickets, 
					float overs) 
	{ 
		this.runRate =(float)runs/overs; 
		this.predictedScore = (int)(this.runRate * 50); 
		display(); 
	} 

	public void display() 
	{ 
		System.out.println("\nAverage Score Display: \n"
						+ "Run Rate: " + runRate + 
						"\nPredictedScore: " + 
						predictedScore); 
	} 
} 

class CurrentScoreDisplay implements Observer 
{ 
	private int runs, wickets; 
	private float overs; 

	public void update(int runs, int wickets, 
					float overs) 
	{ 
		this.runs = runs; 
		this.wickets = wickets; 
		this.overs = overs; 
		display(); 
	} 

	public void display() 
	{ 
		System.out.println("\nCurrent Score Display:\n"
						+ "Runs: " + runs + 
						"\nWickets:" + wickets + 
						"\nOvers: " + overs ); 
	} 
} 

// Driver Class 
class Main 
{ 
	public static void main(String args[]) 
	{ 
		// create objects for testing 
		AverageScoreDisplay averageScoreDisplay = 
						new AverageScoreDisplay(); 
		CurrentScoreDisplay currentScoreDisplay = 
						new CurrentScoreDisplay(); 

		// pass the displays to Cricket data 
		CricketData cricketData = new CricketData(); 

		// register display elements 
		cricketData.registerObserver(averageScoreDisplay); 
		cricketData.registerObserver(currentScoreDisplay); 

		// in real app you would have some logic to 
		// call this function when data changes 
		cricketData.dataChanged(); 

		//remove an observer 
		cricketData.unregisterObserver(averageScoreDisplay); 

		// now only currentScoreDisplay gets the 
		// notification 
		cricketData.dataChanged(); 
	} 
} 

Đầu ra:

Average Score Display: 
Run Rate: 8.823529
PredictedScore: 441

Current Score Display:
Runs: 90
Wickets:2
Overs: 10.2

Current Score Display:
Runs: 90
Wickets:2
Overs: 10.2

Lưu ý:  Bây giờ chúng ta có thể thêm / xóa bao nhiêu người quan sát(observers) mà không cần thay đổi đối tượng cũng được

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!