Tại sao chúng ta cần mẫu thiết kế nhà máy trừu tượng?


124

Hầu hết các định nghĩa nói:

Một nhà máy trừu tượng cung cấp một giao diện để tạo các họ của các đối tượng liên quan mà không chỉ định các lớp cụ thể của chúng

Việc sử dụng Mẫu nhà máy trừu tượng là gì khi chúng ta có thể đạt được nhiệm vụ thông qua việc tạo đối tượng của chính lớp cụ thể. Tại sao chúng ta có một phương thức nhà máy tạo ra đối tượng của lớp Concrete?

Vui lòng cung cấp cho tôi bất kỳ ví dụ thực tế nào trong đó tôi phải triển khai mẫu trừu tượng?

Câu trả lời:


219

Tóm tắt Factory là một mẫu thiết kế rất trung tâm cho Dependency Injection (DI). Dưới đây là danh sách các câu hỏi Stack Overflow trong đó ứng dụng của Tóm tắt Factory đã được chấp nhận làm giải pháp.

Theo sự hiểu biết của tôi, những câu hỏi này đại diện cho những mối quan tâm hoặc vấn đề thực sự mà mọi người gặp phải, vì vậy điều đó sẽ giúp bạn bắt đầu với một số ví dụ thực tế:


6
Tất cả các ví dụ này mô tả Mẫu Phương thức của Nhà máy, vì tất cả chúng đều trả về một giao diện sản phẩm duy nhất. Không ai trong số này là Mô hình Nhà máy Trừu tượng, bởi vì không ai trong số họ tạo ra một họ các giao diện sản phẩm liên quan.
jaco0646

31
Vì lợi ích của việc tiết lộ đầy đủ, tác giả của câu trả lời này nên nói rõ rằng ông cũng là tác giả của mỗi câu trả lời được liên kết; vì vậy danh sách này KHÔNG phải là mẫu đại diện từ cộng đồng SO.
jaco0646

1
@ jaco0646 IIRC, mẫu Phương thức nhà máy là một chuyên môn của mẫu Phương thức mẫu , dựa trên tính kế thừa. Tuy nhiên, tôi có thể nhầm, vì tôi hiện đang đi du lịch và không có cuốn sách GoF của tôi. Ý bạn là gì khi "không ai trong số họ tạo ra một họ các giao diện sản phẩm liên quan"?
Mark Seemann 16/07/2016

1
Manh mối đơn giản nhất cho thấy nhà máy không phù hợp với Mẫu nhà máy trừu tượng là đếm các sản phẩm trừu tượng mà nhà máy sản xuất (tôi đã sử dụng thuật ngữ "giao diện sản phẩm" thay cho "sản phẩm trừu tượng" để tránh lạm dụng từ "trừu tượng") . Một nhà máy sản xuất một sản phẩm trừu tượng duy nhất không thể là Nhà máy Trừu tượng, bởi vì theo định nghĩa, Nhà máy Trừu tượng sản xuất một họ các sản phẩm liên quan . Điều quan trọng cần lưu ý là gia đình này không đề cập đến việc triển khai khác nhau của một giao diện, mà là các sản phẩm có giao diện liên quan khác nhau.
jaco0646

1
Dưới đây là một ví dụ oodesign.com/abab-factory-potype.html . Đây là những gì mô hình nhà máy trừu tượng ban đầu được tạo ra cho.
dùng2802557

23

Một ví dụ thực tế cho việc sử dụng mẫu Tóm tắt của Nhà máy đang cung cấp quyền truy cập dữ liệu vào hai nguồn dữ liệu khác nhau. Giả sử ứng dụng của bạn hỗ trợ các cửa hàng dữ liệu khác nhau. (ví dụ: Cơ sở dữ liệu SQL và tệp XML). Bạn có hai giao diện truy cập dữ liệu khác nhau, ví dụ: IReadableStoreIWritableStorexác định các phương thức phổ biến mà ứng dụng của bạn mong đợi bất kể loại nguồn dữ liệu được sử dụng.

Loại nguồn dữ liệu nào sẽ được sử dụng không nên thay đổi cách mã khách hàng truy xuất các lớp truy cập dữ liệu của nó. Bạn AbstractDataAccessFactorybiết loại nguồn dữ liệu nào được cấu hình và cung cấp một Nhà máy cụ thể cho mã máy khách, tức là SqlDataAccessFactoryhoặc XmlDataAccessFactory. Những nhà máy bê tông có thể tạo ra các triển khai cụ thể, ví dụ SqlReadableStoreSqlWriteableStore.

Các DbProviderFactory trong .NET Framework là một ví dụ về mô hình này.


18
Câu trả lời này có thể mô tả chính xác mẫu Phương thức nhà máy hoặc mẫu Nhà máy tĩnh, nhưng không phải là mẫu Tóm tắt của Nhà máy.
jaco0646

5

Nếu tôi hiểu bạn đúng - câu hỏi là, tại sao chúng ta có cả phương thức Factory và các mẫu nhà máy trừu tượng. Bạn cần nhà máy trừu tượng khi các lớp đa hình khác nhau có quy trình khởi tạo khác nhau. Và bạn muốn một số mô-đun tạo các thể hiện và sử dụng chúng, mà không biết bất kỳ chi tiết nào về khởi tạo đối tượng. Ví dụ: bạn muốn tạo các đối tượng Java thực hiện một số tính toán. Nhưng một số trong số chúng là một phần của ứng dụng, trong khi mã byte khác nên được đọc từ DB. Mặt khác - tại sao chúng ta cần phương pháp nhà máy? Đồng ý, nhà máy trừu tượng đó chồng lên nó. Nhưng trong một số trường hợp - viết mã ít hơn nhiều, có ít lớp và giao diện giúp hệ thống dễ hiểu hơn.


3

Việc sử dụng Mẫu nhà máy trừu tượng là gì khi chúng ta có thể đạt được nhiệm vụ thông qua việc tạo đối tượng của chính lớp cụ thể. Tại sao chúng ta có một phương thức nhà máy tạo ra đối tượng của lớp Concrete?

Khi không có Nhà máy Trừu tượng , Khách hàng cần biết chi tiết về các lớp cụ thể. Khớp nối chặt chẽ này đã được gỡ bỏ với Nhà máy Trừu tượng .

Bây giờ Factory Method cho thấy một hợp đồng, khách hàng đó phải sử dụng. Bạn có thể thêm nhiều sản phẩm vào nhà máy của mình bằng cách thêm các sản phẩm mới, giao diện triển khai theo Phương thức của Nhà máy.

Tham khảo các câu hỏi SE liên quan này để hiểu rõ hơn:

Sự khác biệt cơ bản giữa các mô hình nhà máy và nhà máy trừu tượng là gì?

Ý định:

Cung cấp một giao diện để tạo các họ của 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.

Bạn có thể hiểu ý định, kết cấu, Danh sách kiểm tra và Quy tắc ngón tay cái của Abstract Factory pattern từ này sourcemaking bài viết.

Danh mục:

  1. Quyết định xem các dịch vụ độc lập và sáng tạo nền tảng có phải là nguồn đau hiện tại hay không.
  2. Vẽ ra một ma trận của các nền tảng so với các sản phẩm .
  3. Xác định giao diện xuất xưởng bao gồm phương thức xuất xưởng cho mỗi sản phẩm.
  4. Xác định một lớp dẫn xuất của nhà máy cho mỗi nền tảng đóng gói tất cả các tham chiếu đến toán tử mới.
  5. Khách hàng nên rút tất cả các tham chiếu đến mới và sử dụng các phương thức xuất xưởng để tạo các đối tượng sản phẩm .

2

Các nhà máy trừu tượng rất tốt cho việc hỗ trợ nhiều nền tảng trong khi vẫn giữ cho cơ sở mã của bạn được thống nhất. Giả sử bạn có một chương trình Qt hoặc GTK + hoặc .NET / Mono lớn mà bạn muốn chạy trên Windows, Linux và OSX. Nhưng bạn có một tính năng được triển khai theo một cách khác nhau trên mỗi nền tảng (có thể thông qua API kernel32 hoặc tính năng POSIX).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Với Nhà máy Trừu tượng này, Giao diện người dùng của bạn không cần biết gì về nền tảng hiện tại.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);

1
Tôi không hiểu, làm thế nào khác với việc chỉ sử dụng các phương thức xuất xưởng để trả về một kiểu trừu tượng để khách hàng không biết chi tiết triển khai?
kiwicomb123

1

Nếu bạn nhìn vào các mẫu thiết kế, hầu hết tất cả chúng có thể được làm cho dư thừa. Nhưng mô hình nào có nghĩa là một cách tiếp cận thường được sử dụng cho một giải pháp cho một loại vấn đề tương tự. Một mẫu thiết kế cung cấp cho bạn một cách tiếp cận mức thiết kế hoặc giải pháp cho một tập hợp các loại vấn đề thiết kế tương tự. Sử dụng mẫu thiết kế giúp bạn giải quyết vấn đề của mình và từ đó cung cấp nhanh hơn.


1

thật dễ dàng, hình ảnh rằng bạn có một mã làm việc với sự trừu tượng hóa, bạn nên tạo ra sự trừu tượng và không phải là các lớp cụ thể.

Bạn phải luôn luôn làm việc chống lại sự trừu tượng bởi vì bạn có thể sửa đổi mã tốt hơn.

Đây là một ví dụ điển hình: http://en.wikipedia.org/wiki/ Ab khu_factory_potype # C.23


1

Tôi tìm thấy mô hình Tóm tắt Nhà máy được đánh giá cao.

Trước hết, điều không thường xảy ra là bạn thường có một tập hợp các loại liên quan đến nhau mà bạn muốn khởi tạo.

Thứ hai, mức độ gián tiếp (trừu tượng) được cung cấp bởi các giao diện thường đủ khi làm việc với phép tiêm phụ thuộc.

Ví dụ điển hình của WindowsGui vs MacGui vs ... nơi bạn có WindowsButton, MacButton, WindowsScrollBar, MacScrollbar, v.v. thường dễ thực hiện hơn bằng cách xác định các Nút cụ thể , Thanh cuộn, v.v. hành vi thực tế.


Có một mục đích cụ thể cho nó. với việc tiêm phụ thuộc, bạn không muốn các bộ định vị dịch vụ tiếp tục xuống từ gốc tổng hợp. thay vào đó bạn sử dụng một nhà máy trừu tượng được tiêm.
Adam Tuliper - MSFT

2
tốt ... sử dụng công cụ định vị dịch vụ với DI là một công cụ chống patteren. Một Nhà máy Trừu tượng là giải pháp phổ quát khi chúng ta cần tạo PHỤ THUỘC từ các giá trị thời gian chạy.
TheMentor

1

Tôi nghĩ rằng có một nơi dành cho mẫu nhà máy trừu tượng thay vì mẫu nhà máy đơn giản ở những nơi mà việc khởi tạo của bạn rất phức tạp, quá phức tạp và xấu xí đối với một nhà máy duy nhất và quá phức tạp để UI hiểu được ..

Giả sử đây là nhãn hiệu TYPE_A không phải là một lớp duy nhất .. giả sử có một gia đình gồm 100 loại Loại A tương tự và bạn cần khởi tạo một đối tượng từ chúng. Hãy tưởng tượng có một thông tin tinh vi chi tiết cần thiết để làm cho đối tượng chính xác ra khỏi một thương hiệu của nhiều loại đối tượng tương tự, và trong thực thể đối tượng này, bạn cần biết chính xác các tham số nào để điều chỉnh và làm thế nào để điều chỉnh chúng.

Trong nhà máy đặc biệt cho thương hiệu này, chúng tôi sẽ phân biệt chúng và lấy đối tượng chính xác để khởi tạo và cả cách khởi tạo nó. chúng ta sẽ biết rằng theo đầu vào từ mạng (giả sử màu nào có sẵn trong cửa hàng trực tuyến) và từ các ứng dụng và dịch vụ khác đang chạy trong nền (tham số mà UI không biết về chúng).

Và có thể ngày mai chúng ta sẽ có một gia đình khác, hãy nói type_B và type_C để khởi tạo. Vì vậy, giao diện người dùng sẽ có tính năng nếu khác, nếu người dùng muốn biết nếu người dùng muốn có một kiểu kiểu thì thì kiểu mật mã, kiểu chữ, mật mã, kiểu dữ liệu, nhưng các lớp của nhà máy sẽ quyết định chính xác loại lớp nào (từ gia đình) sẽ xây dựng và làm thế nào để điều chỉnh nó - những giá trị nào cần đặt thành tham số của nó hoặc gửi cho nhà thầu của nó. Tất cả điều này - theo nhiều thông số mà UI không biết. Tất cả điều này sẽ là quá nhiều cho một lớp nhà máy duy nhất.


0

Để trả lời trực tiếp câu hỏi của bạn, có lẽ bạn có thể thoát khỏi mà không cần sử dụng một mẫu thiết kế như vậy.

Tuy nhiên, hãy nhớ rằng hầu hết các dự án trong thế giới thực đều phát triển và bạn muốn cung cấp một số loại khả năng mở rộng để làm cho dự án của bạn trở thành bằng chứng trong tương lai.

Từ kinh nghiệm của riêng tôi, hầu hết thời gian, một Nhà máy được triển khai và khi dự án phát triển, nó được thay đổi thành các mẫu thiết kế phức tạp hơn như Nhà máy Trừu tượng.


0

Đó là tất cả về sự phụ thuộc. Nếu bạn không quan tâm đến sự liên kết chặt chẽ và sự phụ thuộc, thì bạn không cần một nhà máy trừu tượng. Nhưng nó sẽ có vấn đề ngay khi bạn viết một ứng dụng cần bảo trì.


0

Giả sử bạn tạo a.jar và ai đó sử dụng jar của bạn và muốn sử dụng một đối tượng cụ thể mới trong mã của bạn. Nếu bạn không sử dụng nhà máy trừu tượng, thì cô ấy phải sửa đổi mã của bạn hoặc ghi đè mã của bạn. Nhưng nếu bạn đang sử dụng nhà máy trừu tượng, thì cô ấy có thể cung cấp một nhà máy và chuyển mã của bạn và mọi thứ đều ổn.

Phiên bản tinh chỉnh: Hãy xem xét kịch bản dưới đây Người khác đã viết một khung. Khung này sử dụng một nhà máy trừu tượng và một số nhà máy bê tông để tạo ra nhiều đối tượng trong thời gian chạy. Vì vậy, bạn có thể dễ dàng đăng ký nhà máy của riêng bạn vào khung hiện có và tạo các đối tượng của riêng bạn. Khung được đóng để sửa đổi và vẫn dễ dàng mở rộng vì mô hình nhà máy trừu tượng.


0

Mẫu này đặc biệt hữu ích khi khách hàng không biết chính xác nên tạo loại nào. Ví dụ: giả sử một Showroom bán điện thoại di động độc quyền có một truy vấn cho điện thoại thông minh do Samsung sản xuất. Ở đây chúng ta không biết loại đối tượng chính xác sẽ được tạo ra (giả sử tất cả thông tin cho điện thoại được bọc dưới dạng đối tượng cụ thể). Nhưng chúng tôi biết rằng chúng tôi đang tìm kiếm điện thoại thông minh được sản xuất bởi Samsung. Thông tin này thực sự có thể được sử dụng nếu thiết kế của chúng tôi có triển khai nhà máy Tóm tắt.

Hiểu và thực hiện mô hình nhà máy trừu tượng trong C #


0

Ví dụ thực tế được cung cấp trong không gian tên System.Data.Common có các lớp cơ sở trừu tượng bao gồm DbConnection, DbCommand và DbDataAd CHƯƠNG và được chia sẻ bởi các nhà cung cấp dữ liệu .NET Framework, như System.Data.SqlClient và System.Data.OracleClient cho phép nhà phát triển viết mã truy cập dữ liệu chung không phụ thuộc vào nhà cung cấp dữ liệu cụ thể.

Lớp DbProviderFactories cung cấp các phương thức tĩnh để tạo một cá thể DbProviderFactory. Ví dụ sau đó trả về một đối tượng được gõ mạnh dựa trên thông tin nhà cung cấp và chuỗi kết nối được cung cấp trong thời gian chạy.

Thí dụ:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

nhập mô tả hình ảnh ở đây

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Ví dụ-2 nhập mô tả hình ảnh ở đây

Kiến trúc giải pháp mã nhập mô tả hình ảnh ở đây

Các trường hợp nhà máy bê tông được cung cấp bằng phương pháp tĩnh Factory như dưới đây

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.