Sự khác biệt giữa các mẫu thiết kế nhà máy trừu tượng và nhà máy là gì?


454

Tôi biết có nhiều bài viết ngoài kia về sự khác biệt giữa hai mẫu này, nhưng có một vài điều mà tôi không thể tìm thấy.

Từ những gì tôi đã đọc, tôi thấy rằng mẫu phương thức nhà máy cho phép bạn xác định cách tạo một sản phẩm cụ thể nhưng ẩn việc thực hiện khỏi máy khách vì họ sẽ thấy một sản phẩm chung. Câu hỏi đầu tiên của tôi là về nhà máy trừu tượng. Có phải vai trò của nó là cho phép bạn tạo ra các họ vật thể cụ thể trong đó (có thể phụ thuộc vào nhà máy cụ thể bạn sử dụng) chứ không chỉ là một vật cụ thể? Có phải nhà máy trừu tượng chỉ trả về một đối tượng rất lớn hoặc nhiều đối tượng tùy thuộc vào phương thức bạn gọi?

Hai câu hỏi cuối cùng của tôi là về một trích dẫn mà tôi không thể hiểu hết được rằng tôi đã thấy ở nhiều nơi:

Một điểm khác biệt giữa hai loại đó là với mẫu Tóm tắt Factory, một lớp ủy thác trách nhiệm khởi tạo đối tượng cho đối tượng khác thông qua thành phần trong khi mẫu Phương thức Factory 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.

Hiểu biết của tôi là mẫu phương thức nhà máy có giao diện Creator sẽ khiến ConcreteCreator chịu trách nhiệm biết việc sản xuất Concrete Concrete nào. Đây có phải là những gì nó có nghĩa là bằng cách sử dụng kế thừa để xử lý khởi tạo đối tượng?

Bây giờ liên quan đến trích dẫn đó, chính xác thì mẫu Tóm tắt của Nhà máy ủy thác trách nhiệm khởi tạo đối tượng cho đối tượng khác thông qua thành phần như thế nào? Điều đó có nghĩa là gì? Có vẻ như mẫu Tóm tắt của Nhà máy cũng sử dụng tính kế thừa để thực hiện quá trình xây dựng trong mắt tôi, nhưng sau đó tôi vẫn đang tìm hiểu về các mẫu này.

Bất kỳ trợ giúp đặc biệt là với câu hỏi cuối cùng, sẽ được đánh giá rất cao.



Xem "cách cá thể được tạo" từ quan điểm của khách hàng, sẽ giúp bạn hiểu được trích dẫn.
Karthik Bose

@nawfal, câu trả lời trong chủ đề đó thật kinh khủng.
jaco0646

Câu trả lời:


494

Sự khác biệt giữa hai

Sự khác biệt chính giữa "phương thức nhà máy" và "nhà máy trừu tượng" là phương thức nhà máy là một phương thức duy nhất và nhà máy trừu tượng là một đối tượng. Tôi nghĩ rằng rất nhiều người hiểu hai thuật ngữ này và bắt đầu sử dụng chúng thay thế cho nhau. Tôi nhớ rằng tôi đã có một thời gian khó khăn để tìm ra chính xác sự khác biệt khi tôi học chúng.

Bởi vì phương thức nhà máy chỉ là một phương thức, nó có thể được ghi đè trong một lớp con, do đó nửa sau của trích dẫn của bạn:

... Mẫu Phương thức Factory 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.

Các trích dẫn giả định rằng một đối tượng đang gọi phương thức nhà máy riêng của mình ở đây. Do đó, điều duy nhất có thể thay đổi giá trị trả về sẽ là một lớp con.

Nhà máy trừu tượng là một đối tượng có nhiều phương thức nhà máy trên đó. Nhìn vào nửa đầu của trích dẫn của bạn:

... Với mẫu Tóm tắt Factory, một lớp ủy thác trách nhiệm khởi tạo đối tượng cho đối tượng khác thông qua bố cục ...

Điều họ đang nói là có một đối tượng A, người muốn tạo ra một đối tượng Foo. Thay vì tự tạo đối tượng Foo (ví dụ: với phương thức nhà máy), nó sẽ lấy một đối tượng khác (nhà máy trừu tượng) để tạo đối tượng Foo.

Mã ví dụ

Để cho bạn thấy sự khác biệt, đây là một phương pháp được sử dụng:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

Và đây là một nhà máy trừu tượng được sử dụng:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
Đây là một lời giải thích tuyệt vời. Nhưng, phần quan trọng nhất còn lại chưa được trả lời, và đó là: khi nào nên sử dụng một và khi nào mẫu khác?
croraf

11
Không chắc chắn điều này là chính xác. Khá chắc chắn Phương thức Factory là một mẫu thiết kế được đặt tên theo các phương thức của nhà máy, nhưng liên quan đến cấu trúc lớp và sự kế thừa. Nó không phải là một phương pháp duy nhất.
Manila Cohn

2
Vậy có đúng không khi nói: phương thức Factory có thể là một phương thức trong tất cả các lớp thông thường với các mục đích khác nhau. Nhưng Nhà máy Trừu tượng là một lớp / đối tượng được sử dụng bởi một khách hàng và CHỈ chịu trách nhiệm tạo ra một số sản phẩm trong một gia đình?
Hiếu Nguyễn

Việc bạn sử dụng từ "Super" trong "SuperFoo" chỉ có nghĩa là một trường hợp đặc biệt của Foo, hay nó thực sự có nghĩa là siêu hạng? Như tôi giả định nó phải là một lớp con.
dahui

@dahui Vâng, đó là một lớp con. Tôi đã thay đổi nó để SpecialFoorõ ràng hơn.
Tom Dalling

125

Nhà máy trừu tượng tạo ra một lớp cơ sở với các phương thức trừu tượng xác định các phương thức cho các đối tượng cần được tạo. Mỗi lớp nhà máy xuất phát từ lớp cơ sở có thể tạo ra cách thực hiện riêng của từng loại đối tượng.

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

Phương thức Factory chỉ là một phương thức đơn giản được sử dụng để tạo các đối tượng trong một lớp. Nó thường được thêm vào trong tổng hợp gốc ( OrderLớp có một phương thức được gọi là CreateOrderLine)

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

Nhà máy trừu tượng

Trong ví dụ dưới đây, chúng tôi thiết kế một giao diện để chúng tôi có thể tách rời việc tạo hàng đợi từ một hệ thống nhắn tin và do đó có thể tạo các triển khai cho các hệ thống xếp hàng khác nhau mà không phải thay đổi cơ sở mã.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

Phương pháp nhà máy

Vấn đề trong các máy chủ HTTP là chúng tôi luôn cần phản hồi cho mọi yêu cầu.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Nếu không có phương thức xuất xưởng, người dùng máy chủ HTTP (tức là lập trình viên) sẽ bị buộc phải sử dụng các lớp cụ thể thực hiện nhằm đánh bại mục đích của IHttpRequestgiao diện.

Do đó, chúng tôi giới thiệu phương thức nhà máy để việc tạo lớp phản hồi cũng được trừu tượng hóa.

Tóm lược

Sự khác biệt là mục đích dự định của lớp chứa phương thức nhà máy không phải là để tạo đối tượng , trong khi một nhà máy trừu tượng chỉ nên được sử dụng để tạo đối tượng.

Mọi người nên cẩn thận khi sử dụng các phương pháp của nhà máy vì dễ dàng phá vỡ LSP ( nguyên tắc thay thế Liskov ) khi tạo đối tượng.


3
Tại sao chúng ta cần một sản phẩm cụ thể?
Andrew S

60
Vì không ai muốn đầu tư vào ý tưởng.
jgauffin

4
Nhà máy Trừu tượng nên tạo ra nhiều thứ hơn là Button()tạo ra một "gia đình sản phẩm liên quan". Ví dụ, ví dụ GoF chính tắc tạo ScrollBar()Window(). Ưu điểm là Nhà máy Trừu tượng có thể thực thi một chủ đề chung trên nhiều sản phẩm của mình.
jaco0646

Jaco đã đúng. Hãy xem xét rằng cả hai sơ đồ UML về cơ bản là giống nhau (bên cạnh Tóm tắt UML của Factory Factory). Trong cả hai trường hợp, khách hàng đang gọi một phương thức xuất xưởng để tạo một sản phẩm duy nhất.
cobby

1
@AndrewS: Để trả lời câu hỏi của bạn. Nếu chúng ta không cần phải có các sản phẩm cụ thể (các lớp) khác nhau cho cùng một sự trừu tượng hóa (giao diện), thì có lẽ chúng ta cần mẫu xây dựng thay vì không phải mẫu nhà máy. (muộn còn hơn không bao giờ;))
jgauffin

95

Sự khác biệt giữa các mẫu thiết kế của AbstractFactory và Factory như sau:

  • Phương thức nhà máy chỉ được sử dụng để tạo một sản phẩm duy nhất nhưng Nhà máy trừu tượng là về việc tạo ra các họ sản phẩm liên quan hoặc phụ thuộc.
  • Mẫu Phương thức nhà máy hiển thị một phương thức cho khách hàng để tạo đối tượng trong khi trong trường hợp của Nhà máy trừu tượng, họ trưng ra một họ các đối tượng liên quan có thể bao gồm các phương thức Factory này.
  • Mô hình Phương thức nhà máy che giấu việc xây dựng một đối tượng trong khi Nhà máy trừu tượng che giấu việc xây dựng một gia đình của các đối tượng liên quan. Các nhà máy trừu tượng thường được thực hiện bằng cách sử dụng (một bộ) phương pháp nhà máy.
  • Mẫu trừu tượng Factory sử dụng thành phần để ủy thác trách nhiệm tạo một đối tượng cho một lớp khác trong khi mẫu thiết kế Phương thức Factory sử dụng sự kế thừa và dựa vào một lớp dẫn xuất hoặc lớp con để tạo một đối tượng.
  • Ý tưởng đằng sau mẫu Phương thức nhà máy là nó cho phép trong trường hợp khách hàng không biết những lớp cụ thể nào sẽ được yêu cầu tạo trong thời gian chạy, nhưng chỉ muốn có một lớp sẽ thực hiện công việc trong khi mẫu Tóm tắt của Nhà máy sử dụng tốt nhất khi hệ thống của bạn phải tạo nhiều họ sản phẩm hoặc bạn muốn cung cấp thư viện sản phẩm mà không để lộ chi tiết triển khai.!

Thực hiện mô hình phương pháp nhà máy: Phương pháp nhà máy UML

Tóm tắt triển khai mô hình nhà máy:

Nhà máy trừu tượng UML


13
Mmm, không chắc chắn về Ví dụ nhà máy trừu tượng. Tôi nghĩ rằng nhà máy hình dạng và nhà máy màu nên thực hiện các phương pháp tương tự. Nhưng nếu tôi đúng thì mẫu không có ý nghĩa.
Joaquin Iurchuk

4
Các gạch đầu dòng là chính xác; tuy nhiên, cả hai sơ đồ đều sai hoàn toàn và rất sai lệch. Xem sơ đồ bên dưới từ @Trying để biết mô hình chính xác của Nhà máy Trừu tượng.
jaco0646

1
Tôi phải đồng ý rằng 2 sơ đồ thực sự rất sai lệch. Tôi đã nhìn thấy chúng trong trang web hướng dẫn và thành thật mà nói tôi không đồng ý 100% với chúng. Các mô tả có vẻ tốt mặc dù
triển phần mềm

Điều này rất sai lệch.
diyoda_

Hơn 50 upvote và sơ đồ là rất sai. Bằng chứng bạn không thể tin tưởng nhiều câu trả lời mẫu thiết kế trên SO.
Fuhrmanator

27

Sự khác biệt chính giữa Tóm tắt Nhà máy và Phương pháp Nhà máy là Nhà máy Trừu tượng được thực hiện bởi Thành phần ; nhưng Phương thức nhà máy được thực hiện bởi Kế thừa .

Vâng, bạn đã đọc chính xác: sự khác biệt chính giữa hai mẫu này là thành phầnso với tranh luận về thừa kế .

Các sơ đồ UML có thể được tìm thấy trong sách (GoF). Tôi muốn cung cấp các ví dụ mã, bởi vì tôi nghĩ rằng việc kết hợp các ví dụ từ hai câu trả lời hàng đầu trong chủ đề này sẽ cho một minh chứng tốt hơn là chỉ trả lời một mình. Ngoài ra, tôi đã sử dụng thuật ngữ từ cuốn sách trong tên lớp và phương thức.

Nhà máy trừu tượng

  1. Điểm quan trọng nhất cần nắm bắt ở đây là nhà máy trừu tượng được đưa vào máy khách. Đây là lý do tại sao chúng tôi nói rằng Tóm tắt Factory được thực hiện bởi Thành phần. Thông thường, một khung tiêm phụ thuộc sẽ thực hiện nhiệm vụ đó; nhưng một khung không bắt buộc đối với DI.
  2. Điểm quan trọng thứ hai là các nhà máy bê tông ở đây không phải là triển khai Phương thức của Nhà máy! Mã ví dụ cho Phương thức xuất xưởng được hiển thị thêm bên dưới.
  3. Và cuối cùng, điểm thứ ba cần lưu ý là mối quan hệ giữa các sản phẩm: trong trường hợp này là hàng đợi trả lời và trả lời. Một nhà máy bê tông tạo ra hàng đợi Azure, MSMQ khác. GoF đề cập đến mối quan hệ sản phẩm này như một "gia đình" và điều quan trọng cần biết là gia đình trong trường hợp này không có nghĩa là phân cấp lớp.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

Phương pháp nhà máy

  1. Vấn đề quan trọng nhất để nắm bắt ở đây là ConcreteCreator khách hàng. Nói cách khác, máy khách là một lớp con có cha mẹ định nghĩa factoryMethod(). Đây là lý do tại sao chúng tôi nói rằng Phương thức nhà máy được thực hiện bởi Kế thừa.
  2. Điểm quan trọng thứ hai là phải nhớ rằng Mẫu Phương thức của Nhà máy không gì khác hơn là chuyên môn hóa Mẫu Phương thức Mẫu. Hai mẫu chia sẻ một cấu trúc giống hệt nhau. Họ chỉ khác nhau về mục đích. Phương thức Factory là sáng tạo (nó xây dựng một cái gì đó) trong khi Phương thức mẫu là hành vi (nó tính toán một cái gì đó).
  3. Và cuối cùng, điểm thứ ba cần lưu ý là lớp Creator(cha) gọi chính nó factoryMethod(). Nếu chúng ta xóa anOperation()khỏi lớp cha, chỉ để lại một phương thức duy nhất, thì đó không còn là mẫu Phương thức nhà máy nữa. Nói cách khác, Phương thức Factory không thể được thực hiện với ít hơn hai phương thức trong lớp cha; và người ta phải viện dẫn người kia.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

Linh tinh & Mô hình nhà máy Sundry

Xin lưu ý rằng mặc dù GoF xác định hai mẫu Factory khác nhau, nhưng đây không phải là các mẫu Factory duy nhất tồn tại. Chúng thậm chí không nhất thiết là các mẫu Factory được sử dụng phổ biến nhất. Một ví dụ thứ ba nổi tiếng là Mô hình nhà máy tĩnh của Josh Bloch từ Java hiệu quả. Cuốn sách Head First Design Forms bao gồm một mẫu khác mà họ gọi là Simple Factory.

Đừng rơi vào cái bẫy giả định rằng mọi mẫu Factory phải khớp với một mẫu từ GoF.


3
Câu trả lời tuyệt vời và rất rõ ràng dựa trên các ví dụ hay, tốt nhất trong chủ đề này IMO.
Luke Duda

Giải thích tuyệt vời. +1 cho phương thức Factory phải gọi điểm phương thức trừu tượng của nhà máy. Với điểm này thì rõ ràng hơn, không hiểu điểm này: nếu chúng ta có phương thức nhà máy không được gọi bởi nó thì nó sẽ được sử dụng bởi một lớp khác sẽ tạo ra nó và các lớp con của nó sẽ được đưa vào, nó biến thành nhà máy trừu tượng , sự khác biệt trở nên ít rõ ràng hơn nếu điểm mà phương thức nhà máy trừu tượng phải được gọi bởi chính nhà máy giống như mẫu phương thức mẫu không được hiểu
nits.kk

Thêm một câu hỏi-nhận xét. Có nên factoryMethod()luôn luôn là protected phương thức trong mẫu "Phương thức nhà máy"? (Tôi nghĩ là có)
Yaroslav Fedoruk

1
@YaroslavFedoruk, sách GoF cho phép các publicphương thức xuất xưởng và phương thức thậm chí không cần abstract; nhưng điểm quan trọng là phương thức này được dành cho kế thừa, vì vậy nó không thể (ví dụ) là statichoặc final. Tôi đã thực hiện phương pháp protectedabstractở đây để làm nổi bật khả năng mở rộng (bắt buộc).
jaco0646

@ nits.kk, bạn có thể quan tâm đến một câu trả lời liên quan .
jaco0646

26

Tóm tắt Factory là một giao diện để tạo các sản phẩm liên quan, nhưng Factory Method chỉ là một phương thức. Tóm tắt Factory có thể được thực hiện bằng nhiều Phương thức Factory.

Nhà máy trừu tượng UML


10
Bạn đã đăng câu trả lời tương tự ở đây . Nếu bạn cảm thấy rằng câu hỏi này tương tự, thay vào đó hãy đánh dấu nó dưới dạng trùng lặp.
Ja͢ck 18/12/13

11

Xem xét ví dụ này để dễ hiểu.

Các công ty viễn thông cung cấp những gì? Ví dụ, băng thông rộng, đường dây điện thoại và điện thoại di động và bạn được yêu cầu tạo một ứng dụng để cung cấp sản phẩm của họ cho khách hàng của họ.

Nói chung, những gì bạn làm ở đây là, tạo ra các sản phẩm, ví dụ như băng thông rộng, đường dây điện thoại và điện thoại di động thông qua Phương thức xuất xưởng của bạn, nơi bạn biết bạn có những tính chất nào cho các sản phẩm đó và nó khá đơn giản.

Bây giờ, công ty muốn cung cấp cho khách hàng của họ một gói sản phẩm của họ, ví dụ như băng thông rộng, đường dây điện thoại và điện thoại di động, và ở đây có Nhà máy Trừu tượng để chơi.

Tóm lại, Factory Factory là thành phần của các nhà máy khác chịu trách nhiệm tạo ra các sản phẩm của riêng họ và Tóm tắt Factory biết cách đặt các sản phẩm này có ý nghĩa hơn đối với trách nhiệm của chính mình.

Trong trường hợp này, BundleFactoryNhà máy Trừu tượng BroadbandFactory, PhonelineFactoryMobileFactoryFactory. Để đơn giản hóa hơn, các nhà máy này sẽ có Phương thức xuất xưởng để khởi tạo các sản phẩm riêng lẻ.

Lấy mẫu mã dưới đây:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

Hi vọng điêu nay co ich.


1
Không có staticphương pháp nào trong mô hình nhà máy của GoF. Cái này sai.
jaco0646

5

Ví dụ thực tế cuộc sống. (Dễ nhớ)

Nhà máy

Hãy tưởng tượng bạn đang xây dựng một ngôi nhà và bạn tiếp cận một thợ mộc cho một cánh cửa. Bạn đưa ra số đo cho cánh cửa và yêu cầu của bạn, và anh ta sẽ xây dựng một cánh cửa cho bạn. Trong trường hợp này, thợ mộc là một nhà máy sản xuất cửa. Thông số kỹ thuật của bạn là đầu vào cho nhà máy và cửa là đầu ra hoặc sản phẩm từ nhà máy.

Nhà máy trừu tượng

Bây giờ, hãy xem xét ví dụ tương tự của cánh cửa. Bạn có thể đến một thợ mộc, hoặc bạn có thể đến một cửa hàng nhựa hoặc cửa hàng PVC. Tất cả đều là nhà máy sản xuất cửa. Dựa trên tình hình, bạn quyết định loại nhà máy nào bạn cần tiếp cận. Điều này giống như một Nhà máy trừu tượng.

Tôi đã giải thích ở đây cả mẫu phương thức Factory và mẫu nhà máy trừu tượng bắt đầu bằng việc không sử dụng chúng để giải thích các vấn đề và sau đó giải quyết các vấn đề bằng cách sử dụng các mẫu trên https://github.com/vikramnagineni/Design-Potypes/tree/master


3

Chúng ta hãy nói rõ rằng hầu hết thời gian trong mã sản xuất, chúng ta sử dụng mẫu nhà máy trừu tượng vì lớp A được lập trình với giao diện B. Và A cần tạo các thể hiện của B. Vì vậy A phải có một đối tượng nhà máy để tạo ra các thể hiện của B Vì vậy, A không phụ thuộc vào bất kỳ trường hợp cụ thể nào của B. Hy vọng nó có ích.


3

Hiểu sự khác biệt trong các động lực:

Giả sử bạn đang xây dựng một công cụ trong đó bạn có các đối tượng và triển khai cụ thể các mối tương quan của các đối tượng. Vì bạn thấy trước các biến thể trong các đối tượng, bạn đã tạo ra một sự gián tiếp bằng cách giao trách nhiệm tạo các biến thể của các đối tượng cho một đối tượng khác ( chúng tôi gọi đó là nhà máy trừu tượng ). Sự trừu tượng hóa này tìm thấy lợi ích mạnh mẽ vì bạn thấy trước các tiện ích mở rộng trong tương lai cần các biến thể của các đối tượng đó.

Một động lực khá hấp dẫn khác trong dòng suy nghĩ này là một trường hợp trong đó mọi hoặc không ai trong số các đối tượng trong toàn nhóm sẽ có một biến thể tương ứng. Dựa trên một số điều kiện, một trong hai biến thể sẽ được sử dụng và trong mỗi trường hợp, tất cả các đối tượng phải có cùng một biến thể. Điều này có thể hơi phản cảm để hiểu vì chúng ta thường nghĩ rằng - miễn là các biến thể của một đối tượng tuân theo một hợp đồng thống nhất chung ( giao diện theo nghĩa rộng hơn ), mã thực thi cụ thể sẽ không bao giờ bị phá vỡ. Một sự thật thú vị ở đây là, không phải lúc nào điều này cũng đúng, đặc biệt khi hành vi dự kiến ​​không thể được mô hình hóa bằng một hợp đồng lập trình.

Một điều đơn giản ( mượn ý tưởng từ GoF ) là bất kỳ ứng dụng GUI nào nói rằng một màn hình ảo mô phỏng giao diện của MS hoặc Mac hoặc Fedora OS. Ở đây, ví dụ, khi tất cả các đối tượng widget như cửa sổ, nút, v.v. đều có biến thể MS ngoại trừ thanh cuộn có nguồn gốc từ biến thể MAC, mục đích của công cụ thất bại nặng nề.

Những trường hợp trên tạo thành nhu cầu cơ bản của Mẫu nhà máy trừu tượng .

Mặt khác, hãy tưởng tượng bạn đang viết một khung để nhiều người có thể xây dựng các công cụ khác nhau ( chẳng hạn như một trong các ví dụ trên ) bằng cách sử dụng khung của bạn. Theo ý tưởng của một khung công tác, bạn không cần, mặc dù bạn không thể sử dụng các đối tượng cụ thể trong logic của mình. Bạn thay vì đặt một số hợp đồng cấp cao giữa các đối tượng khác nhau và cách chúng tương tác. Mặc dù bạn ( với tư cách là nhà phát triển khung ) vẫn ở mức rất trừu tượng, mỗi người xây dựng công cụ buộc phải tuân theo các cấu trúc khung của bạn. Tuy nhiên, họ ( những người xây dựng công cụ ) có quyền tự do quyết định đối tượng nào sẽ được xây dựng và cách tất cả các đối tượng họ tạo sẽ tương tác. Không giống như trường hợp trước ( của Mẫu nhà máy trừu tượng ), bạn ( với tư cách là người tạo khung) không cần phải làm việc với các đối tượng cụ thể trong trường hợp này; và thay vào đó có thể ở mức hợp đồng của các đối tượng. Hơn nữa, không giống như phần thứ hai của các động lực trước đó, bạn hoặc người xây dựng công cụ không bao giờ có tình huống trộn các đối tượng từ các biến thể. Ở đây, trong khi mã khung vẫn ở mức hợp đồng, mọi nhà xây dựng công cụ bị hạn chế ( theo bản chất của trường hợp ) đối với việc sử dụng các đối tượng của riêng họ. Các sáng tạo đối tượng trong trường hợp này được ủy quyền cho mỗi người triển khai và các nhà cung cấp khung chỉ cung cấp các phương thức thống nhất để tạo và trả về các đối tượng. Các phương thức như vậy là không thể tránh khỏi đối với nhà phát triển khung để tiến hành mã của họ và có một tên đặc biệt gọi là Phương thức Factory ( Mẫu phương thức nhà máy cho mẫu bên dưới ).

Một số lưu ý:

  • Nếu bạn quen thuộc với 'phương thức mẫu', thì bạn sẽ thấy rằng các phương thức xuất xưởng thường được gọi từ các phương thức mẫu trong trường hợp các chương trình liên quan đến bất kỳ dạng khung nào. Ngược lại, các phương thức mẫu của các chương trình ứng dụng thường đơn giản là thực hiện thuật toán cụ thể và làm mất hiệu lực của các phương thức xuất xưởng.
  • Hơn nữa, để hoàn thiện các ý nghĩ, sử dụng khung ( đã đề cập ở trên ), khi người xây dựng công cụ đang xây dựng một công cụ, bên trong mỗi phương thức của nhà máy, thay vì tạo một đối tượng cụ thể, anh ta / cô ta có thể giao thêm trách nhiệm cho một bản tóm tắt đối tượng -factory, được cung cấp trình xây dựng công cụ dự đoán các biến thể của các đối tượng cụ thể cho các phần mở rộng trong tương lai.

Mã mẫu:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. Câu hỏi đầu tiên của tôi là về nhà máy trừu tượng. Có phải vai trò của nó là cho phép bạn tạo ra các họ vật thể cụ thể trong đó (có thể phụ thuộc vào nhà máy cụ thể bạn sử dụng) chứ không chỉ là một vật cụ thể?

Đúng. Mục đích của Tóm tắt Factory là:

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.


  1. Có phải nhà máy trừu tượng chỉ trả về một đối tượng rất lớn hoặc nhiều đối tượng tùy thuộc vào phương thức bạn gọi?

Lý tưởng nhất là nó sẽ trả về một đối tượng cho mỗi máy khách phương thức đang gọi.

  1. Hiểu biết của tôi là mẫu phương thức nhà máy có giao diện Creator sẽ khiến ConcreteCreator chịu trách nhiệm biết việc sản xuất Concrete Concrete nào. Đây có phải là những gì nó có nghĩa là bằng cách sử dụng kế thừa để xử lý khởi tạo đối tượng?

Đúng. Phương pháp nhà máy sử dụng kế thừa.

  1. Tóm tắt mô hình Nhà máy ủy thác trách nhiệm khởi tạo đối tượng cho đối tượng khác thông qua thành phần? Điều đó có nghĩa là gì?

AbstractFactory định nghĩa một FactoryMethod và ConcreteFactory chịu trách nhiệm xây dựng một sản phẩm Concrete. Chỉ cần làm theo thông qua các ví dụ mã trong bài viết này .

Bạn có thể tìm thêm chi tiết trong các bài viết SE liên quan:

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ì?

Mẫu thiết kế: Phương pháp Factory vs Factory vs Tóm tắt Factory


3

Phương thức Factory dựa vào sự kế thừa: Việc tạo đối tượng được ủy quyền cho các lớp con, thực hiện phương thức Factory để tạo đối tượng.

Tóm tắt Factory dựa vào thành phần đối tượng: việc tạo đối tượng được thực hiện theo các phương thức được hiển thị trong giao diện của nhà máy.

Sơ đồ cấp cao của Nhà máy và mô hình nhà máy trừu tượng,

biểu đồ

Để biết thêm thông tin về phương pháp Factory, tham khảo bài viết này .

Để biết thêm thông tin về phương pháp nhà máy trừu tượng, tham khảo bài viết này .


2

Để làm cho nó rất đơn giản với giao diện tối thiểu & vui lòng tập trung "// 1":

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

Ở đây các điểm quan trọng: 1. Các cơ chế Factory & AbstractFactory phải sử dụng tính kế thừa (System.Object-> byte, float ...); Vì vậy, nếu bạn có sự kế thừa trong chương trình thì Factory (Tóm tắt Factory sẽ không có ở đó) bởi thiết kế 2. Người tạo (MyFactory) biết về loại bê tông nên trả về đối tượng loại cụ thể cho người gọi (Chính); Trong loại nhà máy trừu tượng trở lại sẽ là một Giao diện.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

Điểm quan trọng: 1. Yêu cầu: Honda sẽ tạo ra "Thông thường", "Thể thao" nhưng Hero sẽ tạo ra "DarkHorse", "Sports" và "Scooty". 2. tại sao hai giao diện? Một cho loại nhà sản xuất (IVehicleFactory) và một cho nhà máy sản phẩm (IVehicle); Một cách khác để hiểu 2 giao diện là nhà máy trừu tượng là tất cả về việc tạo ra các đối tượng liên quan 2. Điều bắt gặp là các con của IVehicleFactory trở về và IVehicle (thay vì bê tông trong nhà máy); vì vậy tôi nhận được biến cha (IVehicle); sau đó tôi tạo loại cụ thể thực tế bằng cách gọi CreatSingleVehicle và sau đó truyền đối tượng cha vào đối tượng con thực tế. Điều gì sẽ xảy ra nếu tôi làm RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; bạn sẽ nhận được ApplicationException và đó là lý do tại sao chúng tôi cần nhà máy trừu tượng chung chung mà tôi sẽ giải thích nếu được yêu cầu.


1

Nhà máy trừu tượng : Một nhà máy của các nhà máy; một nhà máy tập hợp các nhà máy riêng lẻ nhưng có liên quan / phụ thuộc với nhau mà không chỉ định các lớp cụ thể của họ. Tóm tắt ví dụ nhà máy

Factory : Nó cung cấp một cách để ủy thác logic khởi tạo cho các lớp con. Ví dụ mẫu nhà máy


0

Tôi sẽ ủng hộ Tóm tắt Nhà máy hơn Phương pháp Nhà máy bất cứ lúc nào. Từ ví dụ của Tom Dalling (btw giải thích tuyệt vời) ở trên, chúng ta có thể thấy rằng Nhà máy Trừu tượng có thể kết hợp nhiều hơn ở chỗ tất cả những gì chúng ta cần làm là chuyển một Nhà máy khác đến nhà xây dựng (tiêm phụ thuộc vào nhà xây dựng được sử dụng ở đây). Nhưng Phương thức nhà máy yêu cầu chúng tôi giới thiệu một lớp mới (nhiều thứ hơn để quản lý) và sử dụng phân lớp. Luôn thích thành phần hơn thừa kế.


0

cho phép tôi đặt nó chính xác. hầu hết các câu trả lời đã được giải thích, cung cấp sơ đồ và ví dụ. vì vậy anwer của tôi sẽ chỉ là một lớp lót. từ riêng của tôi: - Mô hình nhà máy trừu tượng của Wikipedia thêm vào lớp trừu tượng qua nhiều triển khai phương thức nhà máy. có nghĩa là nhà máy trừu tượng chứa hoặc kết hợp một hoặc nhiều hơn một mẫu phương thức nhà máy


Điều này LAF không đúng. Đây là quan niệm sai lầm quá phổ biến rằng Nhà máy Trừu tượng không gì khác hơn là một nhà máy của các nhà máy.
jaco0646

0

Rất nhiều câu trả lời ở trên không cung cấp so sánh mã giữa mẫu Tóm tắt Factory và Factory Method. Sau đây là nỗ lực của tôi trong việc giải thích nó thông qua Java. Hy vọng nó sẽ giúp ai đó cần một lời giải thích đơn giản.

Như GoF khéo léo nói: Tóm tắt Factory cung cấp 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.

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

Điều này LAF không đúng. Mã này thực hiện quan niệm sai lầm quá phổ biến rằng Nhà máy Trừu tượng không gì khác hơn là một nhà máy của các nhà máy.
jaco0646

1
@ jaco0646 Tôi tin rằng trong mô hình phương pháp nhà máy, trọng tâm là chỉ lấy một sản phẩm cụ thể ra khỏi FactoryImpl. Trong khi trong mô hình nhà máy trừu tượng, FactoryImpls chịu trách nhiệm cung cấp nhiều Concrete Products tương tự / liên quan, mà giao diện Factory cung cấp hợp đồng. Vì vậy, ZooFactory hoàn toàn không phải là một nhà máy của các nhà máy, như bạn nói, mà chỉ là một giao diện mà Impls cung cấp các Sản phẩm Bê tông có liên quan với nhau. Hãy sửa chữa sự hiểu biết của tôi nếu bạn không đồng ý.
Jatin Shashoo

Trong Phương thức xuất xưởng, trọng tâm là kế thừa thông qua phân lớp, bởi vì Phương thức xuất xưởng là chuyên môn hóa của mẫu Phương thức mẫu. Câu trả lời được bình chọn hàng đầu ở trên cho thấy một ví dụ mã tốt.
jaco0646

@ jaco0646 1. Điều này có nghĩa là trong ví dụ trên, thay vì sử dụng các giao diện cho AnimalFactory và cung cấp các triển khai của nó, tôi nên sử dụng một lớp và ghi đè phương thức createdAnimal () trong các lớp con của nó: CowAnimalFactory, LionAnimalFactory, v.v. ?? 2. Ngoài ra, suy nghĩ của bạn về ví dụ được hiển thị cho ZooFactory là gì ??
Jatin Shashoo

Đối với câu hỏi đầu tiên: có. Đến lần thứ hai, tôi đã thêm câu trả lời của riêng mình cho chủ đề này thay vì tiếp tục phê bình từng câu trả lời riêng lẻ.
jaco0646
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.