So sánh abstract factory pattern và factory pattern năm 2024

Trước tiên, chúng ta hãy cùng cafedev giới thiệu mọi thứ về Abstract Factory Pattern và phần code ví dụ chi tiết nhằm giúp ace dễ hiểu khi áp dụng trên các ngôn ngữ khác nhau. Ace có thể tham khảo thêm các bài khác tại series Design Pattern tại đây.

Nội dung chính

Abstract Factory Factory Pattern là một trong những Creational pattern. Mô hình abstract factory gần giống với Factory Pattern được coi là một Abstract Factory patterns. Các Abstract Factory patterns hoạt động xung quanh một siêu nhà máy tạo ra các nhà máy khác.

Triển khai Abstract factory pattern cung cấp cho chúng ta một khuôn khổ cho phép chúng ta tạo các đối tượng tuân theo một pattern chung. Vì vậy, trong thời gian chạy, abstract factory được kết hợp với bất kỳ factory cụ thể mong muốn nào có thể tạo ra các đối tượng thuộc loại mong muốn.

Hãy xem biểu diễn GOF của pattern

So sánh abstract factory pattern và factory pattern năm 2024

Abstract Factory Design Pattern: Ví dụ về biểu đồ lớp UML cho Abstract Factory Design Pattern.

  • AbstractFactory : Khai báo một giao diện cho các hoạt động tạo các đối tượng sản phẩm trừu tượng.
  • ConcreteFactory : Thực hiện các hoạt động được khai báo trong AbstractFactory để tạo các đối tượng sản phẩm cụ thể.
  • Sản phẩm(Product): Xác định một đối tượng sản phẩm sẽ được tạo ra bởi nhà máy bê tông tương ứng và thực hiện giao diện AbstractProduct.
  • Máy khách(Client): Chỉ sử dụng các giao diện được khai báo bởi các lớp AbstractFactory và AbstractProduct.

Abstract Factory cung cấp các giao diện để tạo họ các đối tượng liên quan hoặc phụ thuộc mà không chỉ định các lớp cụ thể của chúng.

Phần mềm máy khách(Client) tạo ra một triển khai cụ thể của abstract factory và sau đó sử dụng các giao diện chung để tạo ra các đối tượng cụ thể là một phần của họ đối tượng.

Khách hàng(Client) không biết hoặc không quan tâm đến vật thể cụ thể nào mà họ nhận được từ mỗi nhà máy cụ thể này vì họ chỉ sử dụng các giao diện chung của sản phẩm của họ.

Vì vậy, với ý tưởng về mẫu Abstract Factory này, bây giờ chúng ta sẽ cố gắng tạo ra một thiết kế sẽ tạo điều kiện thuận lợi cho việc tạo ra các đối tượng liên quan.

2. Thực hiện

Hãy lấy một ví dụ, Giả sử chúng ta muốn xây dựng một nhà máy sản xuất ô tô toàn cầu. Nếu đó là mẫu thiết kế nhà máy , thì nó phù hợp với một địa điểm duy nhất. Nhưng đối với pattern này, chúng ta cần nhiều vị trí và một số thay đổi thiết kế quan trọng.

Chúng ta cần các nhà máy sản xuất ô tô ở từng địa điểm như IndiaCarFactory, USACarFactory và DefaultCarFactory. Bây giờ, ứng dụng của chúng ta phải đủ thông minh để xác định vị trí nơi ứng dụng đang được sử dụng, vì vậy chúng ta sẽ có thể sử dụng nhà máy sản xuất ô tô phù hợp mà không cần biết việc triển khai nhà máy ô tô nào sẽ được sử dụng trong nội bộ. Điều này cũng giúp chúng ta tránh bị ai đó gọi nhầm nhà máy cho một vị trí cụ thể.

Ở đây chúng ta cần một lớp trừu tượng khác sẽ xác định vị trí và sử dụng nội bộ việc triển khai chính xác nhà máy sản xuất ô tô mà không đưa ra một gợi ý nào cho người dùng. Đây chính xác là vấn đề mà mô hình abstract factory được sử dụng để giải quyết.

// Java Program to demonstrate the  
// working of Abstract Factory Pattern 
enum CarType 
{ 
    MICRO, MINI, LUXURY 
} 
abstract class Car 
{ 
    Car(CarType model, Location location) 
    { 
        this.model = model; 
        this.location = location; 
    } 
    abstract void construct(); 
    CarType model = null; 
    Location location = null; 
    CarType getModel() 
    { 
        return model; 
    } 
    void setModel(CarType model) 
    { 
        this.model = model; 
    } 
    Location getLocation() 
    { 
        return location; 
    } 
    void setLocation(Location location) 
    { 
        this.location = location; 
    } 
    @Override
    public String toString() 
    { 
        return "CarModel - "+model + " located in "+location; 
    } 
} 
class LuxuryCar extends Car 
{ 
    LuxuryCar(Location location) 
    { 
        super(CarType.LUXURY, location); 
        construct(); 
    } 
    @Override
    protected void construct() 
    { 
        System.out.println("Connecting to luxury car"); 
    } 
} 
class MicroCar extends Car 
{ 
    MicroCar(Location location) 
    { 
        super(CarType.MICRO, location); 
        construct(); 
    } 
    @Override
    protected void construct() 
    { 
        System.out.println("Connecting to Micro Car "); 
    } 
} 
class MiniCar extends Car 
{ 
    MiniCar(Location location) 
    { 
        super(CarType.MINI,location ); 
        construct(); 
    } 
    @Override
    void construct() 
    { 
        System.out.println("Connecting to Mini car"); 
    } 
} 
enum Location 
{ 
  DEFAULT, USA, INDIA 
} 
class INDIACarFactory 
{ 
    static Car buildCar(CarType model) 
    { 
        Car car = null; 
        switch (model) 
        { 
            case MICRO: 
                car = new MicroCar(Location.INDIA); 
                break; 
            case MINI: 
                car = new MiniCar(Location.INDIA); 
                break; 
            case LUXURY: 
                car = new LuxuryCar(Location.INDIA); 
                break; 
                default: 
                break; 
        } 
        return car; 
    } 
} 
class DefaultCarFactory 
{ 
    public static Car buildCar(CarType model) 
    { 
        Car car = null; 
        switch (model) 
        { 
            case MICRO: 
                car = new MicroCar(Location.DEFAULT); 
                break; 
            case MINI: 
                car = new MiniCar(Location.DEFAULT); 
                break; 
            case LUXURY: 
                car = new LuxuryCar(Location.DEFAULT); 
                break; 
                default: 
                break; 
        } 
        return car; 
    } 
} 
class USACarFactory 
{ 
    public static Car buildCar(CarType model) 
    { 
        Car car = null; 
        switch (model) 
        { 
            case MICRO: 
                car = new MicroCar(Location.USA); 
                break; 
            case MINI: 
                car = new MiniCar(Location.USA); 
                break; 
            case LUXURY: 
                car = new LuxuryCar(Location.USA); 
                break; 
                default: 
                break; 
        } 
        return car; 
    } 
} 
class CarFactory 
{ 
    private CarFactory()  
    { 
    } 
    public static Car buildCar(CarType type) 
    { 
        Car car = null; 
        // We can add any GPS Function here which 
        // read location property somewhere from configuration 
        // and use location specific car factory 
        // Currently I'm just using INDIA as Location 
        Location location = Location.INDIA;  
        switch(location) 
        { 
            case USA: 
                car = USACarFactory.buildCar(type); 
                break; 
            case INDIA: 
                car = INDIACarFactory.buildCar(type); 
                break; 
            default: 
                car = DefaultCarFactory.buildCar(type); 
        } 
        return car; 
    } 
} 
class AbstractDesign  
{ 
    public static void main(String[] args) 
    { 
        System.out.println(CarFactory.buildCar(CarType.MICRO)); 
        System.out.println(CarFactory.buildCar(CarType.MINI)); 
        System.out.println(CarFactory.buildCar(CarType.LUXURY)); 
    } 
} 

Đầu ra:

Connecting to Micro Car 
CarModel - MICRO located in INDIA
Connecting to Mini car
CarModel - MINI located in INDIA
Connecting to luxury car
CarModel - LUXURY located in INDIA

3. Sự khác biệt

  • Sự khác biệt chính giữa “factory method” và “abstract factory” là factory method là một phương thức duy nhất và abstract factory là một đối tượng.
  • factory method chỉ là một phương thức, nó có thể được ghi đè trong một lớp con, trong khi abstract factory là một đối tượng có nhiều factory method trong đó.
  • Factory Method Pattern sử dụng tính kế thừa và dựa vào một lớp con để xử lý việc khởi tạo đối tượng mong muốn.

4. Ưu điểm

Mẫu này đặc biệt hữu ích khi khách hàng không biết chính xác loại cần tạo.

  • Cách ly các lớp cụ thể: Mẫu Abstract Factory giúp bạn kiểm soát các lớp đối tượng mà ứng dụng tạo ra. Bởi vì một nhà máy đóng gói trách nhiệm và quá trình tạo các đối tượng sản phẩm, nó sẽ cách ly các máy khách khỏi các lớp thực thi. Khách hàng thao tác các phiên bản thông qua các giao diện trừu tượng của họ. Tên lớp sản phẩm được cách ly trong quá trình thực hiện của nhà máy cụ thể; chúng không xuất hiện trong code khách hàng.
  • Trao đổi các họ Sản phẩm một cách dễ dàng: Loại nhà máy cụ thể chỉ xuất hiện một lần trong một ứng dụng, đó là nơi nó được khởi tạo. Điều này giúp dễ dàng thay đổi nhà máy cụ thể mà ứng dụng sử dụng. Nó có thể sử dụng các cấu hình sản phẩm khác nhau chỉ đơn giản bằng cách thay đổi nhà máy cụ thể. Bởi vì một abstract factory tạo ra một họ sản phẩm hoàn chỉnh, toàn bộ họ sản phẩm thay đổi cùng một lúc.
  • Thúc đẩy tính nhất quán giữa các sản phẩm: Khi các đối tượng sản phẩm trong một gia đình được thiết kế để hoạt động cùng nhau, điều quan trọng là ứng dụng chỉ sử dụng các đối tượng từ một gia đình tại một thời điểm. AbstractFactory làm cho điều này dễ dàng thực thi.n.

5. Nhược điểm

  • Khó hỗ trợ các loại sản phẩm mới: Việc mở rộng các abstract factory để sản xuất các loại Sản phẩm mới không phải là điều dễ dàng. Đó là bởi vì giao diện AbstractFactory sửa chữa tập hợp các sản phẩm có thể được tạo. Việc hỗ trợ các loại sản phẩm mới đòi hỏi phải mở rộng factory interface, liên quan đến việc thay đổi lớp AbstractFactory và tất cả các lớp con của nó.

LƯU Ý: Phần nào ví dụ trên cũng dựa trên Cách hoạt động của các Cabs như uber và ola trên quy mô lớn.

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:

  • Full series tự học Design Pattern từ cơ bản tới nâng cao tại đây nha.
  • Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

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: