Mẫu câu hỏi kiểm tra phương pháp nhà máy. Các mô hình sáng tạo. Triển khai cổ điển mẫu Phương thức nhà máy

1. Tên: Phương pháp nhà máy

2. Nhiệm vụ:

    Hệ thống phải duy trì khả năng mở rộng bằng cách thêm các loại đối tượng mới. Không nên sử dụng trực tiếp biểu thức mới vì nó có thể khiến mã tạo đối tượng với các loại cụ thể bị phân tán trong toàn bộ ứng dụng. Khi đó các thao tác như thêm đối tượng thuộc loại mới vào hệ thống hoặc thay thế đối tượng thuộc loại này bằng loại khác sẽ gặp khó khăn (chi tiết hơn trong phần Các mẫu sáng tạo). Mẫu Factory Method cho phép hệ thống duy trì sự độc lập với cả quá trình tạo đối tượng và loại của chúng.

    Người ta biết trước thời điểm tạo một đối tượng nhưng không xác định được loại đối tượng.

3. Giải pháp:

Để đảm bảo rằng hệ thống vẫn độc lập với các loại đối tượng khác nhau, mẫu Factory Method sử dụng cơ chế đa hình - các lớp của tất cả các loại cuối cùng kế thừa từ một lớp cơ sở trừu tượng dành cho sử dụng đa hình. Lớp cơ sở này định nghĩa một giao diện duy nhất thông qua đó người dùng sẽ vận hành các đối tượng thuộc loại cuối cùng.

Để làm cho việc thêm các kiểu mới vào hệ thống trở nên tương đối dễ dàng, mẫu Factory Method bản địa hóa việc tạo các đối tượng thuộc các kiểu cụ thể trong một lớp Factory đặc biệt. Các phương thức của lớp này, thông qua đó các đối tượng của các lớp cụ thể được tạo ra, được gọi là các phương thức xuất xưởng.

Giao diện của các phương thức nhà máy được khai báo trong một lớp nhà máy độc lập và việc triển khai chúng được xác định bởi các lớp con cụ thể của lớp này.

4. Sơ đồ lớp UML của mẫu Factory Method. Triển khai cổ điển

Sản phẩm- bản thân sản phẩm. Được thiết kế để xác định giao diện của các đối tượng được tạo bằng phương thức xuất xưởng;

Sản phẩm bê tông(Máy tính) - các sản phẩm cụ thể tham gia chương trình và chịu trách nhiệm triển khai Sản phẩm (giao diện) lớp trừu tượng.

Người sáng tạo là người sáng tạo và tên của anh ấy đã nói lên điều đó. Đối tượng này nhằm mục đích khai báo một phương thức xuất xưởng trả về một đối tượng thuộc loại Sản phẩm.

Người tạo bê tông- người sáng tạo cụ thể. Ở đây mọi thứ đều rõ ràng: việc triển khai cụ thể của người sáng tạo liên quan đến việc trả lại một sản phẩm cụ thể. Trong ví dụ của chúng tôi, cách triển khai cụ thể của trình tạo là ComputerCreator.

Người sáng tạo tin tưởng các lớp con của nó sẽ triển khai một sản phẩm cụ thể phù hợp. Đó là điểm Phương pháp xuất xưởng.

5. Ví dụ về việc triển khai Phương thức xuất xưởng:

Lớp Sản phẩm nhằm mục đích xác định giao diện của các đối tượng được tạo bằng phương thức xuất xưởng. Đây giống như một lớp vỏ cơ bản cho sản phẩm. Sản phẩm có giá, v.v.

    trừu tượng lớp học Sản phẩm

    công cộng trừu tượng số thập phân Giá mua( lấy; bộ;}

    công cộng trừu tượng số thập phân Giá ( lấy; bộ;}

    công cộng trừu tượng sợi dây Sự miêu tả ( lấy; bộ;}

Chúng ta tạo một lớp kế thừa từ lớp Product, lớp này sẽ gói gọn logic của một sản phẩm cụ thể:

    lớp học Máy tính: Sản phẩm

    riêng tư số thập phân _giá mua;

    riêng tư số thập phân _giá;

    riêng tư sợi dây _Sự miêu tả;

    công cộng Máy tính( sợi dây _Sự miêu tả, số thập phân _giá mua,

    số thập phân _giá)

    cái này._description = _description;

    cái này._purchase_price = _purchase_price;

    cái này._giá = _giá;

    công cộng ghi đè sợi dây Sự miêu tả

    lấy { trở lại _Sự miêu tả; )

    bộ( _description = giá trị; )

    công cộng ghi đè số thập phân Giá

    lấy { trở lại _giá; )

    bộ( _giá = giá trị; )

    công cộng ghi đè số thập phân Giá mua

    lấy { trở lại _giá mua; )

    bộ( _purchase_price = giá trị; )

Hãy mô tả một lớp sáng tạo trừu tượng có phương thức xuất xưởng.

    trừu tượng lớp học Người sáng tạo

    công cộng trừu tượng Phương pháp sản xuất sản phẩm( sợi dây _Sự miêu tả,

    số thập phân _giá mua, số thập phân _giá);

Chúng tôi tạo một lớp cụ thể cho người tạo ra một sản phẩm cụ thể (kế thừa từ Creator). Lớp này định nghĩa một phương thức cho hàm tạo của lớp Máy tính (nếu có nhiều hàm tạo thì mỗi hàm tạo có một phương thức xuất xưởng riêng):

    lớp học ComputerCreator: Người sáng tạo

    công cộng ghi đè Phương pháp sản xuất sản phẩm( sợi dây _Sự miêu tả,

    số thập phân _giá mua, số thập phân _giá)

    trở lại mới Máy tính(_description,_purchase_price,_price);

Mã khách hàng:

    tĩnh trống rỗng Chủ yếu( sợi dây tranh luận)

    Danh sách Danh sách sản phẩm = mới Danh sách

    Người sáng tạo = mới Người sáng tạo;

    người sáng tạo = mới Máy tínhCreator();

    cho mỗi(Người sáng tạo cr TRONG người sáng tạo)

    nếu như(cr Người tạo máy tính)

    ProductList.Add(cr.FactoryMethod("Laptop", 600, 800));

    cho mỗi(Giới thiệu sản phẩm TRONG danh sách sản phẩm)

    Console.WriteLine("Đối tượng lớp (0);\n" +

    "Mô tả: (1);\n" +

    "Giá mua: (2);\n" +

    "Giá bán: (3);\n",

    pr.GetType().Name,

  1. pr.MuaGiá,

Kết quả chương trình:

6. Ưu và nhược điểm của mẫu này:

Nhược điểm rõ ràng nhất của Factory Method là cần phải tạo Creator kế nhiệm bất cứ khi nào bạn dự định mua một loại sản phẩm mới (tức là ConcreteProduct mới). Và điều này, than ôi, không thể tránh khỏi. Nhưng một vấn đề tương tự tồn tại trong nhiều mô hình sinh sản. Ưu điểm bao gồm khả năng tạo các đối tượng phổ quát hơn mà không cần tập trung vào các lớp cụ thể và sử dụng giao diện chung.

Phương pháp xuất xưởng là một mô hình sáng tạo. Mẫu thiết kế này cung cấp một giao diện để tạo các thể hiện của một lớp. Tại thời điểm tạo, những người thừa kế có thể xác định lớp nào sẽ khởi tạo.

Nói cách khác, Nhà máy đại biểu tạo các đối tượng cho con cháu của lớp cha. Điều này cho phép bạn không sử dụng các lớp cụ thể trong mã chương trình mà thao tác các đối tượng trừu tượng ở cấp độ cao hơn.

Mẫu thiết kế Factory rất phổ biến. Hãy xem một ví dụ nhỏ trong Java.

Giới thiệu: Yêu cầu đối với các loại sản phẩm phần mềm không ngừng tăng lên. Báo cáo về việc thực hiện các hoạt động ứng dụng phải được tạo ở các dạng khác nhau: XML, HTML, văn bản, v.v. Đây chính xác là trường hợp thuận tiện khi sử dụng mẫu Factory.

Giải pháp: Lớp Tóm tắtWriter sẽ biểu diễn sự trừu tượng hóa để ghi vào một ngữ cảnh nào đó (có thể là tài liệu XML hoặc tệp văn bản).

Lớp trừu tượng công khai Tóm tắtWriter ( public abstract void write(Object context); )

Lớp này có thể có số lượng con cháu bất kỳ. Chúng ta hãy xem xét các lớp con ConcreteFileWriter và ConcreteXmlWriter để ghi vào tệp văn bản và tài liệu DOM tương ứng:

Lớp công khai ConcreteFileWriter mở rộng Tóm tắtWriter ( public void write (Bối cảnh đối tượng) ( // nội dung phương thức ) ) lớp công khai ConcreteXmlWriter mở rộng Tóm tắtWriter ( public void write (Bối cảnh đối tượng) ( // nội dung phương thức ) )

Để tạo đối tượng chúng ta cần, chúng ta có thể viết Factory sau:

Nhập java.io.File; nhập org.w3c.dom.Document; public class FactoryMethod ( public Tóm tắtWriter getWriter(Object object) ( Tóm tắtWriter writer = null; if (object instanceof File) ( writer = new ConcreteFileWriter(); ) else if (object instanceof Document) ( writer = new ConcreteXmlWriter(); ) return writer ; ) )

Trong văn bản của chương trình, khi tạo báo cáo, bạn cần truyền đối tượng File hoặc tài liệu DOM cho hàm getWriter. Kết quả của việc thực thi phương thức, chúng ta sẽ nhận được đối tượng mong muốn ở mức độ trừu tượng cần thiết.

Sử dụng mẫu Factory trong các trường hợp sau:

  • lớp không có thông tin về loại đối tượng mà nó sẽ tạo;
  • lớp chuyển giao trách nhiệm tạo đối tượng cho lớp con của nó;
  • bạn cần tạo một đối tượng tùy thuộc vào dữ liệu đến.

Trong một trong những bài viết thiết kế tiếp theo, chúng ta sẽ xem xét mẫu Nhà máy trừu tượng.

Trong thời gian chờ đợi, tôi sẽ rất vui khi được lắng nghe những câu hỏi, nhận xét và nhận xét của bạn.



Bình luận: 5

Theo như tôi hiểu, ví dụ này (đặc biệt cảm ơn các ví dụ trong chu trình về các mẫu) minh họa một nhà máy được tham số hóa, vì một tham số được truyền cho phương thức nhà máy, trên cơ sở đó một lớp con Tóm tắt cụ thể được tạo ra. Trong khi đó, nhà máy cổ điển, theo như tôi hiểu, hoạt động hơi khác: “một lớp được thiết kế sao cho các đối tượng mà nó tạo ra được chỉ định bởi các lớp con” (E. Gamma 'Mẫu thiết kế'). Nghĩa là, phải có một số phần tử thừa kế của FactoryMethod cho mỗi phần tử thừa kế của Tóm tắt và việc lựa chọn việc triển khai FactoryMethod nào vẫn thuộc về khách hàng. Tôi đã hiểu đúng chưa?

Trên thực tế, ví dụ này hoàn toàn không hiển thị Factory Method mà chỉ hiển thị cái gọi là Simple Factory (đây thậm chí không phải là một mẫu thiết kế mà chỉ đơn giản là một kỹ thuật được sử dụng rộng rãi). Danik đã viết chính xác rằng lớp FactoryMethod phải có lớp con thực sự ghi đè phương thức xuất xưởng. Thoạt nhìn có vẻ như không có sự khác biệt, nhưng sự khác biệt là rất lớn. Hãy đọc “Mẫu thiết kế đầu tiên” hoặc “Mẫu thiết kế dành cho người mới bắt đầu” và mọi thứ sẽ trở nên rõ ràng với bạn.

Bạn sai rồi. Đây vẫn là một phương pháp nhà máy. Chúng tôi đọc từ Erich Gamma: “các phương pháp sản xuất được tham số hóa. Đây là một biến thể khác của mẫu cho phép phương pháp nhà máy tạo ra các loại sản phẩm khác nhau. Phương thức xuất xưởng được truyền một tham số xác định loại đối tượng được tạo.

Tất cả các đối tượng được tạo ra bằng phương thức Factory đều có chung một giao diện Product. Trong ví dụ về tài liệu, lớp Ứng dụng có thể hỗ trợ các loại tài liệu khác nhau. Bạn đang chuyển một tham số bổ sung cho phương thức CreateDocument để xác định loại tài liệu nào cần được tạo.”

Vì vậy trước khi bày tỏ ý kiến ​​của mình, bạn nên nghiên cứu phần thảm

Tôi không hiểu điều gì đó, điều này khác với chiến lược mẫu như thế nào?

Có lẽ tôi cũng thông minh. Antonin yorov Sự khác biệt giữa nhà máy và chiến lược là chiến lược cho phép bạn xác định linh hoạt thuật toán mong muốn (nghĩa là bạn có thể kết nối lớp con giao diện mong muốn trong thời gian chạy), trong khi nhà máy có một phương thức trong thuật toán trả về một đối tượng .

Trước khi đọc, vui lòng xem lại các quy ước và khái niệm sau. Bài viết này được cập nhật với tần suất nhất định, vì vậy nếu bạn đã đọc nó trước đây thì thực tế không phải là dữ liệu không thay đổi.

Tham khảo lớp tạo ra các mẫu. Chúng được sử dụng để xác định và duy trì mối quan hệ giữa các đối tượng. Các phương thức xuất xưởng loại bỏ yêu cầu người thiết kế phải xây dựng các lớp dành riêng cho ứng dụng vào mã.

Ví dụ

Giả sử chúng ta tạo một trình phân tích cú pháp XML để phân tích tệp được cung cấp và chuyển đổi nó thành cây DOM. Hãy gọi mỗi phần tử của cây này là một nút. Trong khi phân tích cú pháp tệp, chúng ta sẽ phải đối mặt với nhiệm vụ tạo các nút mới và chúng ta sẽ viết vào đó một đoạn mã giống như sau:

Lớp Xml_Node() ( /*...*/ hàm công khai phân tích cú pháp() ( /*...*/ $ChildNode = new Xml_Node(); /*...*/ ) /*...*/ )

Có gì xấu về nó? Hãy để tôi cho bạn ví dụ này: chúng tôi muốn xây dựng một cấu trúc của các đối tượng, một lớp nhất định, dựa trên một tệp XML để sử dụng nó trong tương lai và chúng tôi, theo nguyên tắc “mọi thứ đã được viết cho bạn,” muốn sử dụng lớp XML_Node được tạo sẵn.

Chúng tôi đang tạo XML_Node_Processor kế thừa của riêng mình và bây giờ chúng tôi muốn tác động đến quá trình phân tích tệp để với một thẻ nhất định, một lớp nhất định sẽ được khởi tạo (Đối với thẻ thực phẩm - My_Food, đối với bò - My_Big_Orange_Cow). Và khi thực hiện như trên, để làm được điều này chúng ta sẽ phải đầy đủ nạp chồng phương thức phân tích cú pháp để sao chép-dán mã từ lớp cha bằng cách chỉ chỉnh sửa một dòng mã. Đồng ý, điều này thật ngu ngốc.

Bản chất của mẫu

Có thể triển khai bằng PHP

Lớp trừu tượng XML_Node_Abstract ( hàm trừu tượng createNode($tag); ) lớp Xml_Node mở rộng XML_Node_Abstract ( /*...*/ public function createNode($tag) ( return new Xml_Node(); ) /*...*/ public function pars () ( /*...*/ $ChildNode = $this -> createNode($Tag); /*..*/ ) ) class Xml_Node_Processor mở rộng Xml_Node ( public function createNode($tag) ( switch($tag) ( case "food": return new My_Food(); case "cow": return new My_Big_Orange_Cow(); ) return parent::createNode($tag); ) ) class My_Food mở rộng Xml_Node_Processor (); lớp My_Big_Orange_Cow mở rộng Xml_Node_Processor();

Cuối cùng

  • Trong quá trình thực hiện phương pháp tại nhà máy không phải lúc nào cũng vậy bạn cần một lớp tạo trừu tượng (XML_Node_Abstract). Một trường hợp cụ thể có thể được sử dụng ở vị trí của nó. Từ ví dụ này chúng ta có thể loại bỏ XML_Node_Tóm tắt và sẽ không có gì thay đổi
  • Kết quả được trả về bởi phương thức xuất xưởng phải Luôn luôn tương ứng với một giao diện nhất định (trong trường hợp của chúng tôi là giao diện của lớp Xml_Node)
  • Phương thức xuất xưởng có thể là một hàm tĩnh và có thể được sử dụng để khởi tạo các đối tượng của lớp con
  • Phương pháp nhà máy không cần thiết phải trả về một đối tượng, nó cũng có thể trả về một lớp. Đồng thời, tất cả những người thừa kế và cha mẹ cũng phải trả lại lớp.

Trên thực tế bao gồm các phương pháp nhà máy

Thêm

Câu hỏi

Không hiểu. Vấn đề là trong phương thức phân tích cú pháp của những người thừa kế, các phiên bản của họ chứ không phải cha mẹ được tạo ra?

Tại sao không thay thế:

$ChildNode = Xml_Node mới () ;

không nên làm:

$ChildNode = tĩnh mới; ?

Trả lời

tĩnh mới không giải quyết được vấn đề mà phương thức xuất xưởng được cho là sẽ giải quyết. Nhiệm vụ chính của nó là loại bỏ sự phụ thuộc khỏi mã, sự phụ thuộc vào một lớp cụ thể. Có vẻ như điều này có vấn đề gì? Không có gì. Chính xác cho đến khi bạn cần mở rộng lớp, thêm một số logic hoặc thiết lập thử nghiệm đơn vị.

Hãy tưởng tượng bạn có mã này ở một số nơi:

$node = Xml_Node mới(); $title = $node->getTitle();

Người quản lý dự án đến gặp bạn và nói rằng xml sẽ có hai định dạng khác nhau. Bạn cũng có thể nghĩ:

Nếu ($this -> isFormatOne ()) ( $node = new Xml_Node (); ) else ( $node = new Xml_Node_Extends (); ) $title = $node -> getTitle ();

Sau đó anh ta quay lại và nói rằng bây giờ sẽ có 3.10.500 định dạng. Với kiến ​​trúc như vậy, bạn sẽ phải thực hiện thay đổi TẤT CẢ lần xuất hiện của mã đó MỌI lần. Nếu bạn sử dụng phương thức xuất xưởng, bạn sẽ chỉ phải thay đổi nó và việc tạo một đối tượng sẽ luôn giống nhau:

$node = $this -> createNode(); $title = $node -> getTitle();

Tôi đồng ý rằng bài viết rất hỗn loạn và không bộc lộ hết vẻ đẹp của mẫu này, nhưng tôi có thể nói với bạn rằng đây là một trong những mẫu đơn giản nhất và đồng thời hữu ích. Nếu bạn rèn luyện bản thân, thay vì vô tư tạo ra một đối tượng, ủy thác thao tác này cho người khác, các vấn đề sẽ trở nên ít hơn nhiều.

Phương pháp nhà máy là một mẫu thiết kế tổng quát giải quyết vấn đề tạo ra các sản phẩm khác nhau mà không chỉ định các lớp sản phẩm cụ thể.

Phương thức xuất xưởng chỉ định một phương thức nên được sử dụng thay vì gọi toán tử mới để tạo đối tượng sản phẩm. Các lớp con có thể ghi đè phương thức này để thay đổi loại sản phẩm được tạo.

Các tính năng của mẫu trong Java

Độ phức tạp:

Phổ biến:

Khả năng ứng dụng: Mẫu này thường có thể được tìm thấy trong bất kỳ mã Java nào yêu cầu tính linh hoạt khi tạo sản phẩm.

Mẫu này được sử dụng rộng rãi trong các thư viện chuẩn Java:

  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Trả về các đối tượng đơn lẻ khác nhau, tùy thuộc vào giao thức)
  • javax.xml.bind.JAXBContext#createMarshaller() và các phương thức tương tự khác.

Dấu hiệu sử dụng mẫu: Một phương thức xuất xưởng có thể được xác định bằng các phương thức tạo trả về các đối tượng sản phẩm thông qua các kiểu hoặc giao diện trừu tượng. Điều này cho phép bạn ghi đè các loại sản phẩm được tạo trong các lớp con.

Sản xuất các phần tử GUI đa nền tảng

Trong ví dụ này, sản phẩm là các nút và tác giả là hộp thoại.

Các loại hộp thoại khác nhau có loại phần tử riêng. Do đó, đối với mỗi loại hội thoại, chúng ta tạo lớp con của riêng mình và ghi đè phương thức xuất xưởng trong đó.

Mỗi hộp thoại cụ thể sẽ tạo ra các nút tương ứng với nó. Đồng thời, mã hộp thoại cơ bản sẽ không bị hỏng vì nó chỉ hoạt động với các sản phẩm thông qua giao diện chung của chúng.

nút

nút/Button.java: Giao diện nút chung

gói site.factory_method.example.buttons; /** * Giao diện chung cho tất cả các sản phẩm. */ Nút giao diện công cộng ( void render(); void onClick(); )

nút/HtmlButton.java: Lớp nút cụ thể

gói site.factory_method.example.buttons; /** * Triển khai các nút HTML. */ lớp công khai HtmlButton triển khai Nút ( public void render() ( System.out.println(" "); onClick(); ) public void onClick() ( System.out.println("Click! Nút nói - "Xin chào thế giới!"); ) )

nút/WindowsButton.java: Một loại nút khác

gói site.factory_method.example.buttons; nhập javax.swing.*; nhập java.awt.*; nhập java.awt.event.ActionEvent; nhập java.awt.event.ActionListener; /** * Triển khai các nút hệ điều hành gốc. */ public class WindowsButton thực hiện Nút ( JPanel panel = new JPanel(); JFrame frame = new JFrame(); Nút JButton; public void render() ( frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Xin chào Thế giới!"); label.setOpaque(true); label.setBackground(Màu mới(235, 233, 126)); label.setFont(Phông chữ mới("Dialog", Font. BÓNG, 44)); label.setHorizontalAlignment( SwingConstants.CENTER); panel.setLayout(new FlowLayout(FlowLayout.CENTER)); frame.getContentPane().add(panel); panel.add(label); onClick(); panel.add(button); frame.setSize (320, 200); frame.setVisible(true); onClick(); ) public void onClick() ( nút = new JButton("Exit"); nút.addActionListener(new ActionListener() ( public void actionPerformed(ActionEvent e) ( frame.setVisible(false); System.exit(0); ) )); ) )

nhà máy

nhà máy/Dialog.java:Đối thoại cơ bản

gói site.factory_method.example..factory_method.example.buttons.Button; /** * Lớp cơ sở của nhà máy. Lưu ý rằng "nhà máy" chỉ là * một vai trò bổ sung cho lớp. Nó đã có một số logic kinh doanh * yêu cầu tạo ra nhiều loại sản phẩm. */ public abstract class Dialog ( public void renderWindow() ( // ... phần còn lại của mã hộp thoại... Button okButton = createButton(); okButton.render(); ) /** * Các lớp con sẽ ghi đè phương thức này để tạo các đối tượng sản phẩm * cụ thể, khác nhau cho từng nhà máy. */ public abstract Button createButton(); )

nhà máy/HtmlDialog.java: Lớp đối thoại cụ thể

gói site.factory_method.example..factory_method.example.buttons..factory_method.example.buttons.HtmlButton; /** * Hộp thoại HTML. */ lớp công khai HtmlDialog mở rộng Hộp thoại ( @Override public Button createButton() ( return new HtmlButton(); ) )

nhà máy/WindowsDialog.java: Một lớp đối thoại khác

gói site.factory_method.example..factory_method.example.buttons..factory_method.example.buttons.WindowsButton; /** * Hộp thoại về các thành phần của hệ điều hành. */ public class WindowsDialog mở rộng Hộp thoại ( @Override public Button createButton() ( return new WindowsButton(); ) )

Demo.java: Mã khách hàng

gói site.factory_method..factory_method.example.factory..factory_method.example.factory.Html.factory_method.example.factory.WindowsDialog; /** * Lớp demo. Đây là nơi tất cả kết hợp với nhau. */ Bản trình diễn lớp công khai ( hộp thoại Hộp thoại tĩnh riêng; public static void main(String args) ( configure(); runBusinessLogic(); ) /** * Ứng dụng tạo một nhà máy cụ thể tùy thuộc vào cấu hình hoặc * môi trường. */ static void configure () ( if (System.getProperty("os.name").equals("Windows 10")) ( hộp thoại = new WindowsDialog(); ) else ( hộp thoại = new HtmlDialog(); ) ) /** * Mọi mã máy khách khác chỉ tương tác với nhà máy và sản phẩm * thông qua một giao diện chung, do đó, không quan trọng nhà máy nào * được tạo. */ static void runBusinessLogic() ( hộp thoại.renderWindow(); ) )

Đầu raDemo.txt: Kết quả với nhà máy HtmlDialog

Nhấp chuột! Nút nói - "Xin chào thế giới!"

Mục đích của mẫu Factory Method

Hệ thống thường cần tạo các đối tượng thuộc nhiều loại khác nhau. Mẫu Factory Method có thể hữu ích trong việc giải quyết các vấn đề sau:

  • Hệ thống phải duy trì khả năng mở rộng bằng cách thêm các loại đối tượng mới. Không nên sử dụng trực tiếp biểu thức mới vì nó có thể khiến mã tạo đối tượng với các loại cụ thể bị phân tán trong toàn bộ ứng dụng. Khi đó các thao tác như thêm loại đối tượng mới vào hệ thống hoặc thay thế đối tượng thuộc loại này bằng loại khác sẽ khó khăn (để biết thêm chi tiết, xem phần Tạo mẫu). Mẫu Factory Method cho phép hệ thống duy trì sự độc lập với cả quá trình tạo đối tượng và loại của chúng.
  • Người ta biết trước thời điểm tạo một đối tượng nhưng không xác định được loại đối tượng.

Mô tả mẫu Factory Method

Để đảm bảo rằng hệ thống vẫn độc lập với các loại đối tượng khác nhau, mẫu Factory Method sử dụng cơ chế đa hình - các lớp của tất cả các loại cuối cùng kế thừa từ một lớp cơ sở trừu tượng dành cho sử dụng đa hình. Lớp cơ sở này định nghĩa một giao diện duy nhất thông qua đó người dùng sẽ vận hành các đối tượng thuộc loại cuối cùng.

Để làm cho việc thêm các kiểu mới vào hệ thống trở nên tương đối dễ dàng, mẫu Factory Method bản địa hóa việc tạo các đối tượng thuộc các kiểu cụ thể trong một lớp Factory đặc biệt. Các phương thức của lớp này, thông qua đó các đối tượng của các lớp cụ thể được tạo ra, được gọi là các phương thức xuất xưởng. Có hai loại mẫu Phương thức nhà máy:

Hàm tạo chung , khi một phương thức xuất xưởng tĩnh được định nghĩa trong cùng một lớp cơ sở đa hình mà từ đó các lớp dẫn xuất của tất cả các kiểu được tạo trong hệ thống kế thừa. Mã định danh loại của đối tượng được tạo phải được truyền dưới dạng tham số cho phương thức này.

Phiên bản cổ điển của phương pháp nhà máy , khi giao diện của các phương thức xuất xưởng được khai báo trong một lớp xuất xưởng độc lập và việc triển khai chúng được xác định bởi các lớp con cụ thể của lớp này.

Triển khai mẫu Phương thức nhà máy

Hãy xem xét cả hai lựa chọn để triển khai mẫu Phương thức nhà máy bằng cách sử dụng ví dụ về quy trình tạo nhân vật quân sự cho trò chơi chiến lược của chúng ta. Mô tả chi tiết của nó có thể được tìm thấy trong phần Generative Patterns. Để đơn giản hóa mã demo, chúng tôi sẽ tạo các ký tự quân sự cho một số đội quân trừu tượng mà không tính đến đặc điểm của các bên tham chiến.

Triển khai mẫu Phương thức nhà máy dựa trên hàm tạo chung

// #bao gồm #bao gồm enum Warrior_ID ( Bộ binh_ID=0, Archer_ID, Horseman_ID ); // Phân cấp các lớp nhân vật trong game class Warrior ( public: virtual void info() = 0; virtual ~Warrior() () // Phương thức xuất xưởng tĩnh được tham số hóa static Warrior* createWarrior(Warrior_ID id); ); lớp Lính bộ binh: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; } }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; } }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; } }; // Реализация параметризированного фабричного метода Warrior* Warrior::createWarrior(Warrior_ID id) { Warrior * p; switch (id) { case Infantryman_ID: p = new Infantryman(); break; case Archer_ID: p = new Archer(); break; case Horseman_ID: p = new Horseman(); break; default: assert(false); } return p; }; // Создание объектов при помощи параметризированного фабричного метода int main() { vectorv; v.push_back(Warrior::createWarrior(Infantryman_ID)); v.push_back(Warrior::createWarrior(Archer_ID)); v.push_back(Warrior::createWarrior(Horseman_ID)); for(int i=0; i thông tin(); // ... )

Phiên bản được trình bày của mẫu Factory Method rất phổ biến do tính đơn giản của nó. Trong đó, phương thức tĩnh createWarrior() được định nghĩa trực tiếp trong lớp cơ sở Warrior đa hình. Phương thức xuất xưởng này được tham số hóa, nghĩa là để tạo một đối tượng thuộc một loại nhất định, mã định danh loại tương ứng sẽ được chuyển tới createWarrior().

Từ quan điểm về “sự thuần khiết” của mã hướng đối tượng, tùy chọn này có những nhược điểm sau:

  • Vì mã để tạo các đối tượng thuộc tất cả các loại có thể tập trung vào phương thức xuất xưởng tĩnh của lớp Warrior, nên lớp Warrior cơ bản có kiến ​​thức về tất cả các lớp bắt nguồn từ nó, điều này không điển hình cho cách tiếp cận hướng đối tượng.
  • Việc sử dụng câu lệnh switch như thế này (như trong mã cho phương thức xuất xưởng createWarrior()) cũng không được khuyến khích trong lập trình hướng đối tượng.

Những nhược điểm này không có trong quá trình triển khai cổ điển của mẫu Factory Method.

Triển khai cổ điển mẫu Phương thức nhà máy

// #bao gồm #bao gồm // Phân cấp các lớp nhân vật trong game class Warrior ( public: virtual void info() = 0; virtual ~Warrior() () ); lớp Lính bộ binh: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; }; }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; }; }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; }; }; // Фабрики объектов class Factory { public: virtual Warrior* createWarrior() = 0; virtual ~Factory() {} }; class InfantryFactory: public Factory { public: Warrior* createWarrior() { return new Infantryman; } }; class ArchersFactory: public Factory { public: Warrior* createWarrior() { return new Archer; } }; class CavalryFactory: public Factory { public: Warrior* createWarrior() { return new Horseman; } }; // Создание объектов при помощи фабрик объектов int main() { InfantryFactory* infantry_factory = new InfantryFactory; ArchersFactory* archers_factory = new ArchersFactory ; CavalryFactory* cavalry_factory = new CavalryFactory ; vectorv; v.push_back(bộ binh_factory->createWarrior()); v.push_back(archers_factory->createWarrior()); v.push_back(cavalry_factory->createWarrior()); for(int i=0; i thông tin(); // ... )

Phiên bản cổ điển của mẫu Factory Method sử dụng ý tưởng về một nhà máy đa hình. Lớp cơ sở đa hình Factory, đặc biệt dành riêng cho việc tạo các đối tượng, khai báo giao diện của phương thức nhà máy createWarrior() và các lớp dẫn xuất của nó triển khai nó.

Phiên bản được trình bày của mẫu Factory Method là phiên bản phổ biến nhất nhưng không phải là phiên bản duy nhất. Có thể có các biến thể sau:

  • Lớp Factory có cách triển khai mặc định của phương thức nhà máy createWarrior().
  • Phương thức xuất xưởng createWarrior() của lớp Factory được tham số hóa theo loại đối tượng được tạo (giống như Phương thức Factory đơn giản được trình bày trước đó) và có cách triển khai mặc định. Trong trường hợp này, các lớp có nguồn gốc từ Nhà máy chỉ cần thiết để xác định hành vi không chuẩn của createWarrior() .

Kết quả áp dụng mẫu Factory Method

Ưu điểm của mẫu Factory Method

  • Tạo các đối tượng thuộc các loại khác nhau, cho phép hệ thống duy trì sự độc lập với chính quá trình tạo và với các loại đối tượng được tạo.

Nhược điểm của mẫu Factory Method

  • Trong trường hợp phiên bản cổ điển của mẫu, thậm chí để tạo một đối tượng duy nhất, cần phải tạo một nhà máy tương ứng