2011-01-22 37 views
33

Từ When would you use the Builder Pattern?,Builder Vs Decorator pattern

Người ta nói rằng mẫu xây dựng phù hợp cho ví dụ về Pizza.

Tại sao không phải trang trí? bằng cách xử lý Pho mát, Pepperoni, Thịt xông khói làm đồ trang trí bổ sung trên bánh pizza cơ sở.

Có phải vì lý do mà Pho mát/Pepperoni phải được xây dựng riêng biệt. Tôi không nghĩ rằng, họ cần phải được xây dựng riêng biệt khi họ có thể có sẵn readymade.

Xin làm rõ. Tôi cũng đang tìm kiếm một ví dụ thực tế tốt về kiểu trang trí và lý do tại sao nó là ví dụ thích hợp cho ví dụ cụ thể đó. Cảm ơn bạn.

+0

tôi đã có suy nghĩ tương tự khi tôi học được điều này với ví dụ. Giáo sư không thể giúp tôi, nhưng điều này không, cảm ơn! – Mene

Trả lời

36

Từ bài viết Decorator Pattern wikipedia của:

Trong lập trình hướng đối tượng, các trang trí hoa văn là một mẫu thiết kế cho phép mới/bổ sung hành vi để được thêm vào một đối tượng hiện động.

Không cần phải thêm lớp trên bề mặt vào Pizza sau khi đã được xây dựng hoàn chỉnh. Bạn không ăn một nửa bánh pizza và sau đó thêm một bánh khác để nó.

Nói cách khác, các mẫu Builder giúp bạn dễ dàng xây dựng một đối tượng mà được mở rộng theo các hướng độc lập tại thời gian thi công, trong khi các mẫu Decorator cho phép bạn thêm phần mở rộng các chức năng cho một đối tượng sau thời gian thi công. Việc sử dụng mẫu trang trí để xây dựng các đối tượng là xấu vì nó rời khỏi đối tượng trong trạng thái không nhất quán (hoặc ít nhất là không chính xác) cho đến khi tất cả các trình trang trí được yêu cầu - tương tự như vấn đề JavaBean khi sử dụng các bộ định vị để xác định các đối số hàm tạo tùy chọn.

+1

potter: Trên thực tế, một số toppings như kitchup, ớt mảnh sẽ được đưa ra cùng với Pizza. Vì vậy, chúng ta có thể nói chúng ta áp dụng cả hai mẫu? Người xây dựng đầu tiên sau đó là Decorator? – bjskishore123

+0

potter: +1, giả định của tôi ở trên dường như là chính xác về lớp trên bề mặt, có được từ http://stackoverflow.com/questions/2707401/please-help-me-understand-the-decorator-pattern-with-real-world- ví dụ – bjskishore123

+3

@bjs: vâng, người trang trí và người xây dựng có thể được kết hợp một cách hợp lý và ví dụ của bạn là một khả năng; tuy nhiên, nó dẫn đến một thiết kế phức tạp và ít mã dễ đọc hơn. Tôi chỉ sử dụng Builder + Decorator nếu tôi chắc chắn nó thực sự được yêu cầu bởi dự án và không chỉ là trường hợp "Pattern Fever" trên phần của tôi.Hãy xem xét liệu nó có thể có giá trị chỉ cần thêm một phương thức 'addChilli()' vào lớp cơ sở chứ không phải là xây dựng một 'ChilliDecorator' đầy đủ. (Như mọi khi, không có câu trả lời chính xác.) –

20

Bạn đang bối rối hai điều rất khác nhau. GoF phân loại Builder như là một mô hình sáng tạo, trong khi Decorator là một mô hình kết cấu. Chúng được mô tả như sau (Gamma et al, trang 1):

Builder (97) Tách việc xây dựng một đối tượng phức tạp từ đại diện của mình để quá trình thi công tương tự có thể tạo ra cơ quan đại diện khác nhau.

Trang trí (175) Đính kèm thêm trách nhiệm cho đối tượng một cách linh hoạt. Trang trí cung cấp giải pháp thay thế linh hoạt cho phân lớp để mở rộng chức năng.

Lưu ý sự nhấn mạnh trên trang trí. Đó là một sự thay thế linh hoạt cho phân lớp phụ. Phân lớp được sử dụng để mô hình hóa mối quan hệ là mối quan hệ. Pho mát không phải là pizza. Các bánh pizza là sáng tác của một số thành phần, và thường được mô hình hóa bằng cách sử dụng chế phẩm.

Mẫu trình xây dựng có liên quan ở đây vì có rất nhiều thành phần cần thiết để xây dựng chúng theo cách được chuẩn hóa.

Để lấy một ví dụ thực tế về trang trí, gần đây tôi muốn ghi lại các truy vấn được thực hiện bằng cách sử dụng jdbc trong ứng dụng java của tôi. Tôi thực hiện điều này bằng cách thực hiện một lớp gọi là LoggingConnection, mở rộng giao diện Connection.

public class LoggingConnection implements Connection 
{ 
    public static class LogEntry 
    { 
     public String sql; 
     public int invocationCount; 
     public double avgTime; 
     public double maxTime; 
    } 

    private Connection delegate; 

    private Map<String, LogEntry> log; 

    public LoggingConnection(Connection delegate) 
    { 
     this.delegate = delegate; 
     this.log = new HashMap<String, LogEntry>(); 
    } 

    public Map<String, LogEntry> getLog() 
    { 
     return log; 
    } 

    @Override 
    public void clearWarnings() 
    throws SQLException 
    { 
     delegate.clearWarnings(); 
    } 

    @Override 
    public void close() 
    throws SQLException 
    { 
     delegate.close(); 
    } 

    // forwarding declarations to all other methods declared in the interface 
    ... 
} 

Điều này cho phép tôi thực hiện kết nối cụ thể và mở rộng chức năng của nó khi chạy. Phân lớp phụ sẽ có vấn đề trong ngữ cảnh này, bởi vì bạn không nhất thiết phải biết đối tượng kết nối nào thực sự được trả về. Điều này là do nó được xây dựng cho bạn sử dụng nhà máy DriverManager:

Connection conn = DriverManger.getConnection(dsn); 

Đối tượng conn trong trường hợp này là một thực hiện chứa trong trình điều khiển mà tôi không biết tên. Cách tiếp cận trang trí của beuty là tôi không cần phải biết, và nó không liên quan đến việc thực hiện cụ thể.

+1

Vâng, một "thay thế" cho thấy rằng phân lớp cũng có thể được sử dụng. Cách thay thế subclassing không phải là làm cho phô mai trở thành một phân lớp của pizza, mà đúng hơn là có một lớp con pizza _pizza_. Vì pizza phô mai là pizza. –

+0

@ Lèse: Nhưng có thể hiểu rằng bạn có thể triển khai một trình trang trí thêm chức năng "phô mai" giống như một lớp con. Sự khác biệt lớn duy nhất là bạn có thể quyết định làm cho phần mở rộng trong thời gian chạy thay thế. –

+0

+1: Hữu ích, Cảm ơn bạn. – bjskishore123

1

Mẫu trình xây dựng được sử dụng cụ thể để xây dựng và Trang trí để thêm các tính năng đặc biệt của bài đăng. ví dụ: Trong ví dụ về Pizza ở trên, chúng tôi có thể quyết định sử dụng một trong hai mẫu dựa trên miền sự cố.

Nếu Chilli Flakes rất cần thiết cho Pizza và tương tự, chúng tôi có rất nhiều nguyên liệu để thêm vào Pizza, trong đó có ít nguyên liệu để làm cho Pizza ăn được (trạng thái có ý nghĩa), chúng ta có thể sử dụng Builder. Khi Pizza được xây dựng, sau đó chúng tôi có thể đi và trang trí nó với các lớp phủ khác nhau như nước sốt cà chua, ô liu, ...

Ngoài ra, nó có thể được sử dụng cùng nhau nhưng điều này sẽ làm tăng độ phức tạp. Vì vậy, chúng ta nên sử dụng các mẫu một cách khôn ngoan chỉ khi nó là cần thiết trong lĩnh vực vấn đề, khác xây dựng đơn giản là đủ.

2

Cho phép đi qua các đặc điểm chính của BuilderTrang trí.

Builder: (A mẫu Creational)

  1. Quá nhiều lý lẽ để vượt qua từ chương trình khách hàng đến lớp Nhà máy có thể được dễ bị lỗi
  2. Một số các thông số có thể tùy chọn không giống như trong máy mà lực lượng để gửi tất cả các thông số
  3. Đối tượng nặng và sự sáng tạo của nó rất phức tạp. ví dụ. xây dựng nhiều loại hình pizza

Decorator: (Một mô hình cấu)

  1. Thêm hành vi phản đối tại thời gian chạy. Thừa kế là chìa khóa để đạt được chức năng này, đó là cả lợi thế và bất lợi của mô hình này.
  2. Nó tăng cường hành vi của giao diện.
  3. Trang trí có thể được xem dưới dạng Biến thể tổng hợp chỉ với một thành phần. Tuy nhiên, một Decorator bổ sung thêm các trách nhiệm bổ sung - nó không dành cho tập hợp đối tượng.
  4. Decorator hỗ trợ thành phần đệ quy
  5. Decorator được thiết kế để cho phép bạn thêm trách nhiệm với các đối tượng mà không cần phụ classing

Khi sử dụng Decorator:

  1. trách nhiệm Object và hành vi phải được thêm/xóa một cách linh động
  2. triển khai bê tông nên được tách riêng từ trách nhiệm và hành vi
  3. Khi phụ - classing là quá tốn kém để tự động thêm/gỡ bỏ trách nhiệm

Trở lại với câu hỏi của bạn:

Builder là mẫu creational phù hợp với Pizza. Pizza được tạo ra với các thành phần bắt buộc ban đầu (Bánh mì, vv). Phô mai, Pepperoni, Bacon là các thành phần tùy chọn nhưng chúng vẫn có thể là một phần của bánh pizza trong quá trình chế biến.

Trang trí hữu ích khi thêm các trách nhiệm động vào thời gian chạy cho đối tượng đã tạo.

ví dụ: :

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt"))); 

Tham khảo bài viết dưới đây để biết thêm chi tiết:

Keeping builder in separate class (fluent interface)

When to Use the Decorator Pattern?

Các vấn đề liên quan