Factory Method trong thực tiễn

Giả sử như bạn cần mua một chiếc máy tính, nhưng bạn vẫn chưa quyết định được nên sử dụng máy tính của hãng nào. Ngoài kia bao la bạt ngàn những thương hiệu chất lượng cao như Apple, Lenovo, Asus, HP… Như vậy để có thể chọn được chiếc máy tính ưng ý, bạn sẽ có 2 cách sau:

– Đến showroom của từng hãng, rồi tham khảo từng máy. Bạn đi hết showroom của hãng này tới showroom của hãng khác để xem, rồi nhớ thông tin trong đầu để so sánh chiếc này hợp hơn, chiếc kia rẻ hơn …

– Bạn đến một cửa hàng bày bán tất cả các loại laptop của tất cả các hãng, rồi bạn hỏi tư vấn là với số tiền này, bạn có thể chọn được laptop loại nào. Hay bạn đang muốn xem thử máy của hãng A, bạn nhờ tư vấn viên mang ra giúp bạn một chiếc. Rồi bạn băn khoăn một chiếc của hãng B, bạn lại nhờ tư vấn viên mang ra một chiếc khác.

Rõ ràng là cách thứ hai tiết kiệm thời gian và công sức cho bạn rất nhiều. Đây chính là cách mà mẫu thiết kế Factory hoạt động.

Mẫu thiết kế factory là gì?

Factory pattern là một mẫu thiết kế thuộc nhóm Khởi tạo. Pattern này sử dụng một interface hay một abstract class mà tất cả các lớp chúng ta cần khởi tạo đối tượng sẽ kế thừa. Factory sẽ định nghĩa việc khởi tạo đối tượng, nhưng đối tượng nào sẽ được tạo thì phụ thuộc vào các lớp con. Do vậy, pattern này còn được gọi với cái tên Virtual Constructor (phương thức khởi tạo ảo).

Factory pattern mang lại những tác dụng:

– Tạo ra một cách khởi tạo object mới

– Che giấu quá trình xử lý logic của phương thức khởi tạo

– Giảm sự phụ thuộc, dễ dàng mở rộng trong trường hợp chưa biết chắc số lượng đối tượng là đã đủ hay chưa. Trong trường hợp chúng ta có thêm lớp con kế thừa Factory, việc gọi đến virtual constructor vẫn không hề thay đổi.

– Giảm khả năng gây lỗi compile, trong trường hợp chúng ta cần tạo một đối tượng mà quên khai báo lớp, chúng ta cũng có thể xử lý lỗi trong Factory và khai báo lớp cho chúng sau.

Cấu trúc của Factory pattern

Xét theo ví dụ ở đầu bài viết, Factory pattern sẽ có cấu trúc dạng như sau:

Các lớp con Lenovo, Asus, HP đều override lại phương thức getSpec từ interface Computer. Phương thức viewComputer() của client sẽ  gọi tới phương thức viewComputer của lớp ComputerFactory và truyền vào đó một tham số computerBrand, chính là tên của máy tính mà client muốn xem thêm, để tạo một đối tượng tương ứng. Đối tượng này sẽ được sử dụng để chạy phương thức view mà lớp con đã override lại.

Factory pattern trong Java

Trong ví dụ trên, nếu chúng ta làm theo cách 1, mã nguồn sẽ có dạng như sau:

```
public class Client {
	public void viewComputer() {
		public void ViewLenovo() {
			Lenovo lenovoComputer = new Lenovo();
			System.out.println(lenovoComputer.getSpec());
		}

		public void ViewAsus() {
			Asus asusComputer = new Asus();
			System.out.println(asusComputer.getSpec());
		}

		public void ViewHP() {
			HP hpComputer = new HP();
			System.out.println(hpComputer.getSpec());
		}
	}
}

```

Như vậy, client sẽ phải gọi đến từng constructor cụ thể của từng lớp để tạo được đối tượng mong muốn. 

Vậy khi áp dụng Factory pattern, mã nguồn sẽ thế nào?

Bước 1: Xây dựng lớp factory:

```
public class ComputerFactory {
	public void viewComputer(String computerBrand) {
		Computer computer;
		switch (computerBrand) {
			case "Lenovo":
				computer = new Lenovo();
				break;
			case "Asus":
				computer = new Asus();
				break;
			case "HP":
				computer = new HP();
				break;
			default:
				System.out.println("Computer brand not found");
				break;
		}
		if (computer != null) {
			System.out.println(computer.getSpec());
		}
	}
}
```

Bước 2: Từ lớp client, chúng ta gửi chỉ thị đến Factory:

```
public class Client {
	public void viewComputer() {
		ComputerFactory computerFactory = new ComputerFactory();
		computerFactory.viewComputer("Lenovo");
		computerFactory.viewComputer("HP");
		computerFactory.viewComputer("Asus");
		computerFactory.viewComputer("Dell");
	}
}
```

Như vậy, việc khởi tạo các đối tượng thuộc từng lớp kế thừa interface Computer đã bị ẩn đi đối với client. Mặt khác, khi chúng ta thêm mới lớp kế thừa Computer, chỉ có virtual constructor trong Factory cần cập nhật, thay vì phải thay đổi trên cả lớp Client.


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: