Chào mừng bạn đến với ví dụ về mẫu thiết kế Abstract Factory trong Java ( Abstract Factory Design Pattern in Java). Abstract Factory là một trong những mẫu thiết kế thuộc nhóm Creational patterns. Abstract Factory pattern gần giống với Factory Pattern, điểm khác biệt là nó giống như một “nhà máy của các nhà máy” – tức là nó tạo ra các Factory khác nhau.

Abstract Factory
Nếu bạn đã quen với factory design pattern trong Java, bạn sẽ nhận thấy rằng chúng ta chỉ có một lớp Factory duy nhất. Lớp factory này sẽ trả về các lớp con (sub-class) khác nhau dựa vào đầu vào, thường sử dụng cấu trúc if-else hoặc switch để thực hiện điều này.
Trong Abstract Factory pattern, chúng ta loại bỏ khối if-else đó và tạo một lớp factory riêng cho mỗi lớp con. Sau đó sẽ có một lớp Abstract Factory dùng để trả về lớp con tương ứng thông qua lớp factory cụ thể.
Thoạt đầu có vẻ khó hiểu, nhưng khi bạn nhìn vào phần cài đặt, sẽ thấy khá dễ hiểu và dễ phân biệt sự khác nhau giữa Factory và Abstract Factory pattern. Giống như bài viết về factory pattern trước đây, chúng ta sẽ sử dụng cùng một lớp cha (superclass) và các lớp con.
Abstract Factory Design Pattern – Lớp cha và các lớp con
Computer.java
package com.journaldev.design.model;
public abstract class Computer {
public abstract String getRAM();
public abstract String getHDD();
public abstract String getCPU();
@Override
public String toString(){
return "RAM= "+this.getRAM()+", HDD="+this.getHDD()+", CPU="+this.getCPU();
}
}
PC.java
package com.journaldev.design.model;
public class PC extends Computer {
private String ram;
private String hdd;
private String cpu;
public PC(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
Server.java
package com.journaldev.design.model;
public class Server extends Computer {
private String ram;
private String hdd;
private String cpu;
public Server(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
Lớp Factory cho mỗi lớp con
Trước tiên, chúng ta cần tạo một interface hoặc lớp abstract ****cho Abstract Factory.
ComputerAbstractFactory.java
package com.journaldev.design.abstractfactory;
import com.journaldev.design.model.Computer;
public interface ComputerAbstractFactory {
public Computer createComputer();
}
Chú ý rằng phương thức createComputer() sẽ trả về một instance của lớp cha Computer. Bây giờ các lớp factory của chúng ta sẽ triển khai interface này và trả về lớp con tương ứng.PCFactory.java
package com.journaldev.design.abstractfactory;
import com.journaldev.design.model.Computer;
import com.journaldev.design.model.PC;
public class PCFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public PCFactory(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public Computer createComputer() {
return new PC(ram,hdd,cpu);
}
}
Tương tự, chúng ta sẽ có một lớp factory cho lớp con Server. ServerFactory.java
package com.journaldev.design.abstractfactory;
import com.journaldev.design.model.Computer;
import com.journaldev.design.model.Server;
public class ServerFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public ServerFactory(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public Computer createComputer() {
return new Server(ram,hdd,cpu);
}
}
Bây giờ, chúng ta sẽ tạo một lớp consumer để cung cấp điểm khởi đầu cho các lớp client khi muốn tạo ra các lớp con. ComputerFactory.java
package com.journaldev.design.abstractfactory;
import com.journaldev.design.model.Computer;
public class ComputerFactory {
public static Computer getComputer(ComputerAbstractFactory factory){
return factory.createComputer();
}
}
Lưu ý rằng đây là một lớp đơn giản và phương thức getComputer nhận một đối tượng ComputerAbstractFactory làm tham số và trả về một đối tượng Computer. Ở thời điểm này, phần cài đặt chắc chắn đã trở nên rõ ràng hơn. Hãy viết một phương thức kiểm thử đơn giản để xem cách sử dụng abstract factory để lấy instance của các lớp con. TestDesignPatterns.java
package com.journaldev.design.test;
import com.journaldev.design.abstractfactory.PCFactory;
import com.journaldev.design.abstractfactory.ServerFactory;
import com.journaldev.design.factory.ComputerFactory;
import com.journaldev.design.model.Computer;
public class TestDesignPatterns {
public static void main(String[] args) {
testAbstractFactory();
}
private static void testAbstractFactory() {
Computer pc = com.journaldev.design.abstractfactory.ComputerFactory.getComputer(new PCFactory("2 GB","500 GB","2.4 GHz"));
Computer server = com.journaldev.design.abstractfactory.ComputerFactory.getComputer(new ServerFactory("16 GB","1 TB","2.9 GHz"));
System.out.println("AbstractFactory PC Config::"+pc);
System.out.println("AbstractFactory Server Config::"+server);
}
}
Output của chương trình trên sẽ là:
AbstractFactory PC Config::RAM= 2 GB, HDD=500 GB, CPU=2.4 GHz
AbstractFactory Server Config::RAM= 16 GB, HDD=1 TB, CPU=2.9 GHz
Đây là sơ đồ lớp (class diagram) của phần cài đặt abstract factory design pattern.

Lợi ích của Abstract Factory Design Pattern
- Abstract Factory cung cấp cách tiếp cận lập trình hướng interface thay vì cụ thể vào implementation.
- Abstract Factory là một “nhà máy của các nhà máy” và có thể dễ dàng mở rộng để hỗ trợ thêm sản phẩm mới, ví dụ như thêm lớp con Laptop và một lớp factory LaptopFactory.
- Abstract Factory mang tính mở rộng cao và tránh được logic điều kiện (if-else) như trong Factory pattern.
Ví dụ sử dụng Abstract Factory Design Pattern trong JDK
- javax.xml.parsers.DocumentBuilderFactory#newInstance()
- javax.xml.transform.TransformerFactory#newInstance()
- javax.xml.xpath.XPathFactory#newInstance()
Video hướng dẫn về Abstract Factory Design Pattern
Gần đây tôi có đăng một video trên YouTube về abstract factory design pattern. Trong video đó, tôi chia sẻ khi nào và làm sao để triển khai mẫu thiết kế này. Tôi cũng đã giải thích sự khác nhau giữa factory pattern và abstract factory design pattern.
Bạn có thể tải mã ví dụ từ dự án GitHub của tôi.