Khi viết mã hướng đối tượng, tôi có nên luôn tuân theo một mẫu thiết kế không?


37

Có một mẫu thiết kế có thể hiểu được cho bất kỳ chương trình hướng đối tượng? Tôi hỏi điều này bởi vì gần đây tôi thấy một Doorlớp thực hiện với một Lock. Đó là một phần của thử nghiệm và câu trả lời nói rằng mã đang theo mẫu Null Object:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

Điều này làm tôi nghĩ: Mã này tuân theo một mẫu thiết kế tốt mặc dù mô tả rất đơn giản (lớp này đang thiết kế một lớp cửa có khóa), vì vậy nếu tôi viết mã phức tạp hơn, thì phải luôn có một số mẫu thiết kế mà tôi đang theo dõi?



51
Bạn có nghĩ rằng bạn có thể nói hoàn toàn bằng thành ngữ? Không? Sau đó, bạn không nên xây dựng các chương trình của mình bằng cách ghép các mẫu thiết kế lại với nhau.
Kilian Foth

4
Trong ví dụ của bạn, mẫu đối tượng Null chỉ được thêm vào cho mục đích học thuật, nó không đưa "thiết kế tốt" vào mã này.
Doc Brown

4
@djechlin: nói cách khác, sử dụng mẫu thiết kế "hai từ" :)
Michael Shaw

11
Vấn đề là quá nhiều người tin rằng các mẫu thiết kế là sự thay thế cho suy nghĩ và thay thế cho kinh nghiệm (ngụ ý một số lượng thử nghiệm và lỗi nhất định). Bạn không thể lấy một cuốn sách có đầy đủ các mẫu thiết kế và ghép chúng lại với nhau như Đồ chơi Tinker để tạo ra một ứng dụng có kích thước không tầm thường, độ phức tạp và chất lượng khá. Ngay cả các lập trình viên có kinh nghiệm thường cần phải thử hai hoặc ba thiết kế trước khi họ tìm thấy một thiết kế hoạt động.
Daniel R Hicks

Câu trả lời:


143

phải luôn luôn có một số mẫu thiết kế mà tôi đang theo dõi?

Lạy Chúa KHÔNG!

Ý tôi là, bạn có thể tiếp tục và nói rằng bất kỳ mã ngẫu nhiên nào đang theo một số mẫu XYZ ngẫu nhiên, nhưng điều đó không hữu ích hơn tôi tự nhận là vua của chiếc ghế máy tính của mình. Không ai khác thực sự biết điều đó có nghĩa là gì và ngay cả những người không thực sự tôn trọng yêu cầu của tôi.

Các mẫu thiết kế là một công cụ giao tiếp để các lập trình viên có thể nói với các lập trình viên khác những gì đã được thực hiện hoặc những gì nên làm mà không mất nhiều thời gian để lặp lại. Và vì chúng là những thứ xuất hiện rất nhiều lần, chúng là những khái niệm hữu ích cho các lập trình viên học "này, làm cho XYZ dường như luôn xuất hiện bởi vì nó tốt / hữu ích".

Chúng không thay thế nhu cầu bạn tự suy nghĩ, điều chỉnh các mô hình cho vấn đề duy nhất trước mặt bạn hoặc xử lý tất cả những điều không thể tránh khỏi không phù hợp với những chiếc xô đẹp.


5
Đoạn đầu tiên của bạn là một phần của cách tôi sẽ trả lời điều này. Một cái gì đó trở thành một mô hình khi nó được lặp đi lặp lại. Nếu nó được lặp đi lặp lại đủ số lần để yêu cầu giao tiếp, thì đó là Mẫu và lợi ích từ một cái tên. Nó thậm chí còn được lập luận bởi một số mô hình chỉ phát triển vì thiếu một số trừu tượng. Theo đuổi các mô hình là con đường để trở thành một thành viên của tổ chức vận chuyển hàng hóa được ca tụng.
Magus

11
@Cerad: Chắc chắn, miễn là bạn hứa sẽ không viết các lớp Chúa nữa!
yatima2975

9
John Doe - Kỹ sư kỹ thuật, Monkey Code chung và Vua của chiếc ghế máy tính của anh ấy
hjk

1
Có thể cho rằng, một thiết kế nên sử dụng các mẫu khi thích hợp và các lớp nên được đặt tên như vậy. Chúng là công cụ quan trọng. Việc sợ the_cult(tm) cũng nguy hiểm không kém.
Gusdor

25
Câu trả lời chính xác! Một chỉ trích của tôi là "Lạy Chúa KHÔNG!" không đủ lớn
tobyink

37

Không.

Đây là những gì Gang of Four (người ban đầu phổ biến các mẫu thiết kế) đã nói về nó trong cuốn sách của họ :

"Không có cuộc thảo luận nào về cách sử dụng các mẫu thiết kế sẽ hoàn tất nếu không có một vài từ về cách không sử dụng chúng. Các mẫu thiết kế không nên được áp dụng một cách bừa bãi. Thường thì chúng đạt được sự linh hoạt và thay đổi bằng cách đưa ra các mức độ bổ sung và điều đó có thể làm phức tạp một thiết kế và / hoặc chi phí cho bạn một số hiệu suất. Một mẫu thiết kế chỉ nên được áp dụng khi sự linh hoạt mà nó thực sự cần thiết. "

Ví dụ bạn cho thấy không thực sự làm được gì nhiều (tôi không nghĩ nó có ý nghĩa, tôi nghĩ nó chỉ là một ví dụ). Chính nó, nó không cần mẫu đối tượng null. Trong bối cảnh của một chương trình lớn hơn, nó có thể.

Cách tiếp cận sai lầm cho rằng chỉ vì nó được gắn mác "mẫu thiết kế" thì nó phải tốt, và sau đó tìm kiếm nhiều nơi hơn để nhồi nhét nhiều mẫu hơn. Sử dụng chúng khi chúng phù hợp với chương trình và thực sự giải quyết vấn đề cho bạn.


7
Cuốn sách đang được thiết kế mẫu: Các yếu tố của phần mềm hướng đối tượng có thể tái sử dụng của Erich Gamma, Richard Helm, Ralph Johnson và John Vlissides.
developerwjk

4
+1 Để thực sự trích dẫn nguồn của các mẫu thiết kế.
Pharap

29

Nếu tôi đang viết mã phức tạp hơn, có nên luôn có một số mẫu thiết kế mà tôi đang theo không?

Không. Các mẫu thiết kế chỉ là: các mẫu trong mối quan hệ giữa các đối tượng. Nói cách khác, các mối quan hệ được sử dụng và tái sử dụng thường đủ để ai đó nói rằng "Này, chúng ta dường như đang làm điều này rất nhiều, hãy đặt tên cho nó." Danh sách các mẫu thiết kế không được xác định cùng một lúc vào đầu OOP và sau đó được GOF lưu truyền ! Chúng được phát hiện và cuối cùng được ghi lại, và sau đó được phổ biến bởi cuốn sách.

Điều đó nói rằng, một phần lớn lợi ích của các mẫu thiết kế là chúng giúp dễ dàng suy nghĩ về thiết kế phần mềm ở mức cao hơn. Họ cho phép bạn bỏ qua lo lắng về chi tiết thực hiện và suy nghĩ nhiều hơn về bức tranh lớn. Theo nghĩa đó, họ giải phóng bạn khỏi những chi tiết vụn vặt, nhưng họ cũng có thể giới hạn bạn theo cách mà cách bạn thể hiện bản thân có thể bị giới hạn bởi những từ mà bạn biết. Vì vậy, có thể trải qua một thời gian khi có một mẫu thiết kế cho hầu hết những gì bạn làm chỉ đơn giản là vì các mô hình mà bạn biết là các điều khoản trong đó bạn nghĩ. Hãy để mắt mở cho những trường hợp bạn có thể đang lạm dụng một mô hình và nơi bạn có thể cần suy nghĩ sâu hơn về những cách tốt hơn để làm mọi việc.

Ngoài ra, nhận ra rằng trong thực tế, bạn thường không triển khai một mẫu thiết kế nhất định nhiều như nhận ra mẫu trong một số mã hiện có, như khung đối tượng. Biết về các mẫu thiết kế phổ biến giúp dễ dàng hơn nhiều để tìm hiểu cách sử dụng một khung công tác vì bạn có thể thấy các mối quan hệ giữa các lớp theo thuật ngữ mà bạn đã hiểu.


10

Mẫu thiết kế có hai ưu điểm.

  1. Chúng rất dễ mô tả cho các nhà phát triển khác, bởi vì mọi người thường đồng ý về các mẫu đó là gì
  2. Họ có xu hướng bị đánh bại khá chu đáo bởi những người tiền nhiệm của chúng tôi, vì vậy điểm mạnh và điểm yếu của họ được hiểu rõ.

Mục tiêu của mọi chương trình nên là

  1. Nó hoạt động. Nó phải làm bất kể mục tiêu cuối cùng là gì, hoặc không quan trọng bạn sử dụng bao nhiêu mẫu thiết kế. Các mẫu thiết kế OO giúp dễ dàng giải quyết vấn đề thành các bit dễ hiểu để dễ chứng minh nó hoạt động hơn.
  2. Nó rất dễ đọc. Đây là nơi các mẫu thiết kế là tốt đẹp. Các vấn đề OO họ giải quyết rất phức tạp. Nếu bạn giải quyết chúng theo cách "chuẩn", thì nhà phát triển tiếp theo sẽ dễ dàng hơn
  3. Nó rất dễ trồng. Gần 0 chương trình hiện đại kết thúc nơi mọi người lên kế hoạch cho họ. Mỗi chương trình phát triển sau khi phát hành ban đầu. Các mẫu OO được biết đến là rất tốt trong việc phát triển.

Điều đó đã được nói, lưu ý rằng mọi tham chiếu đến các mẫu thiết kế OO là "họ chỉ giỏi trong công việc". Chúng không hoàn hảo, nhưng chúng lấp đầy một ngách rất hiệu quả. Sử dụng chúng khi chúng làm việc, tránh chúng khi chúng không.

Ví dụ, về "mã phức tạp", như bạn đã đề cập trong câu hỏi của mình, hãy sử dụng ngôn ngữ kịch bản mà tôi đã viết. Hầu hết trong số đó là OO với các mẫu thiết kế ở khắp mọi nơi. Tuy nhiên, khi viết về trình thu gom rác, tôi đã bỏ qua tất cả các giả vờ của OO, bởi vì những điều đặc biệt tôi cần làm được mô hình hóa tốt hơn như cách bash bit thời trang tốt. Không có một mẫu OO nào trong toàn bộ cho đến khi viết ra các bản hoàn thiện, trong đó một lần nữa OO lại bắt đầu trở thành một mô hình hữu ích. Không có bất kỳ sự hào hoa hay hoàn cảnh nào, mã đột nhiên chuyển trở lại sử dụng các kỹ thuật OO một lần nữa.

Sử dụng các mẫu thiết kế bất cứ khi nào họ làm cho sản phẩm của bạn tốt hơn; tránh chúng khi chúng làm cho sản phẩm của bạn tệ hơn


2
Tôi nghĩ rằng câu cuối cùng nên ở đầu in đậm hoặc tóm tắt.
Pharap

5

Tôi sẽ bỏ qua xu hướng một chút, bởi vì câu trả lời tinh tế hơn những câu trả lời khác đang được đưa ra. Mỗi lớp bạn viết không nên sử dụng một mẫu thiết kế, nhưng hầu hết các chương trình không tầm thường bạn viết có thể nên.

Một chương trình không tầm thường mà không có bất kỳ mẫu thiết kế nào chỉ ra:

  • Chương trình của bạn độc đáo đến nỗi không có phần nào giống với các vấn đề phổ biến mà các lập trình viên gặp phải trước đây. Hoặc là
  • Chương trình của bạn chứa những vấn đề phổ biến đó, nhưng bạn đã giải quyết chúng theo cách tốt hơn mà trước đây không ai nghĩ đến.

Cả hai kịch bản đều rất khó xảy ra, không có hành vi phạm tội.

Điều đó không có nghĩa là mẫu thiết kế sẽ điều khiển thiết kế của bạn hoặc bạn nên chèn một cách bừa bãi vì bạn nghĩ nó sẽ trông tệ nếu bạn không làm vậy. Các mẫu thiết kế sai là tồi tệ hơn không có.

Điều đó có nghĩa là bạn nên xem việc thiếu các mẫu thiết kế trong chương trình tổng thể của bạn như một mùi mã. Một cái gì đó khiến bạn có cái nhìn thứ hai và đánh giá lại nếu thiết kế của bạn không thể sạch hơn. Nếu tại thời điểm đó, bạn quyết định loại bỏ các mẫu thiết kế ra khỏi một chương trình, thì đó phải là một quyết định có chủ ý, được thông báo, không xảy ra.

Ví dụ, bạn không nói, "Tôi cần lập mô hình cửa và khóa, tôi nên sử dụng mẫu thiết kế nào?" Tuy nhiên, nếu bạn thiết kế nó trước mà không sử dụng bất kỳ mẫu thiết kế nào, điều đó sẽ nhắc bạn sau đó nói điều gì đó như: "Tôi có rất nhiều kiểm tra null trong mã này, tôi tự hỏi liệu có một mẫu thiết kế nào có thể giúp quản lý chúng không."

Thấy sự khác biệt? Đó là một sự khác biệt tinh tế nhưng quan trọng.


5
Có nhiều vấn đề phổ biến hơn (và giải pháp chung của chúng) so với các mẫu thiết kế. Các mẫu thiết kế là một tập hợp con được phân loại theo danh mục của các giải pháp OO phổ biến - không phải là tập hợp của tất cả các giải pháp phổ biến.
Michael Shaw

1
Bạn có thể định nghĩa những gì bạn có nghĩa là 'không tầm thường', tôi có ấn tượng rằng thuật ngữ 'không tầm thường' là chủ quan.
Pharap

1
Đó là chủ quan. Ý tôi là loại chương trình bạn sẽ viết cho một nhóm tại nơi làm việc, đòi hỏi nhiều người bảo trì trên cơ sở liên tục.
Karl Bielefeldt

Nếu bạn đủ may mắn để nhìn thấy vấn đề của bạn sau đó. Null kiểm tra, chắc chắn. Lỗ hổng bảo mật? Những cách xảo quyệt khác chương trình sẽ phá vỡ trong bảo trì? Vấn đề chỉ kỹ sư tiếp theo sẽ phát hiện ra? May mắn hơn nhiều.
djechlin

"Tôi cần lập mô hình một cánh cửa và khóa, giao diện nên là gì? Hiệu suất sẽ là một phần của hợp đồng? Tôi có nên sử dụng dịch vụ hoặc thư viện không? Tài nguyên sẽ được thông qua như thế nào?" tất cả nên được hỏi, và bạn nên có câu trả lời về cơ bản được coi là mẫu thiết kế.
djechlin

4

Câu hỏi hỏng. Để tôi cung cấp cho bạn một định nghĩa mới về mẫu thiết kế sẽ hoàn tác rất nhiều thiệt hại do GoF phát hành: một mẫu thiết kế là một thực hành mã hóa tốt . Đó là nó.

Bất kỳ mô-đun hợp lý phức tạp sẽ có một số mẫu thiết kế trong đó. Bất cứ khi nào bạn lưu trữ bộ nhớ cache đó có thể là một mô hình bay bổng nhưng tôi sẽ không thu hồi bằng cấp lập trình của bạn nếu bạn không gọi nó là như vậy. Bất cứ khi nào bạn có một cuộc gọi lại trong đó, bạn đang ở trong một kiểu mẫu sự kiện / lửa / gọi lại nào đó. vv Nếu bạn có từ "tĩnh", bạn có một singleton. Nếu bạn có một hàm tạo tĩnh, bạn có một mẫu nhà máy. Nếu một tài nguyên được chuyển đến mô-đun của bạn, bạn đang sử dụng phép nội xạ phụ thuộc.

"Mẫu thiết kế" là một thuật ngữ bị hỏng phổ biến bởi GoF, làm cho nó có vẻ như tất cả các mẫu đều ở cùng cấp độ hoặc bạn nên sử dụng bác sĩ khuyến nghị 3 đến 5 mỗi lớp. Bất cứ khi nào bạn làm điều gì đó đúng mà người khác đã làm đúng, đó là một mẫu thiết kế . A for(;;)là một mẫu phổ biến được sử dụng để đại diện cho một vòng lặp vô hạn, ví dụ.

Bạn không nên cố gắng học một loạt các mẫu thiết kế. Kiến thức lập trình không được lập chỉ mục bởi các mẫu thiết kế! Thay vào đó, bạn nên học cách viết mã tốt bằng cách đọc sách, blog và tham dự các hội nghị trong lĩnh vực của bạn. Chẳng hạn, nếu bạn đã sử dụng phương thức tiêm phụ thuộc nhưng chưa dán nhãn, bạn có thể được lợi từ việc luôn sử dụng DI hoặc sử dụng khung IoC. Hoặc nếu bạn đang vật lộn để viết mã ngay trong các sự kiện và cuộc gọi lại, hãy tìm hiểu Haskell để bạn quen thuộc với các mẫu thiết kế chức năng và nó trở nên dễ dàng.

Và nếu toàn bộ lớp học của bạn đọc là một điều lớn mà người khác đã làm đúng, tại sao bạn lại phát minh lại bánh xe? Chỉ cần sử dụng công cụ của họ.


2
Trong ngôn ngữ nào là for(;;)thành ngữ? Đó có lẽ không phải là ví dụ tốt nhất về điều mà ai đó đã "đúng".
Telastyn

1
@Telastyn C, C ++, Java, Javascript, C #.
djechlin

2
Tôi chưa bao giờ thấy ai thích điều đó hơn while(true)(hoặc while(1)) trong C, C ++, Java hoặc C # trong hơn 20 năm lập trình của tôi.
Telastyn

1
@Telastyn stackoverflow.com/a/2611744/1339987 fwiw Tôi bắt đầu thích trong khi (đúng) bởi vì nó có vẻ dễ đọc hơn đối với tôi.
djechlin

1
Tôi luôn luôn sử dụng cho (;;). Không có lý do cụ thể, tôi đọc nó ở đâu đó có lẽ. Tôi thích thực tế không có biến hoặc hằng số liên quan. Dù sao, @Telastyn bây giờ bạn đã gặp ai đó .
Kiến

0

Bạn phải luôn tuân theo các nguyên tắc thiết kế OO (ví dụ: mô đun hóa, ẩn thông tin, độ gắn kết cao, v.v.). Các mẫu thiết kế là một phân khúc tương đối tinh tế của các nguyên tắc thiết kế OO, đặc biệt nếu bạn xem xét nguyên tắc KISS .

Các mẫu là giải pháp cho các vấn đề thiết kế phổ biến. Những vấn đề này đến từ một trong hai nơi (hoặc kết hợp cả hai): không gian vấn đề (ví dụ: phần mềm để quản lý Nhân sự trong một công ty) và không gian giải pháp . Một chương trình OO là một ví dụ trong không gian giải pháp (ví dụ: một trong nhiều cách bạn có thể thiết kế chương trình OO để tạo thuận lợi cho việc quản lý nhân sự).

Thật không dễ dàng để biết khi nào nên sử dụng một mẫu. Một số mẫu ở mức độ thấp, gần với mã hóa và không gian giải pháp (ví dụ: Singleton, Null object, Iterator). Những người khác được thúc đẩy bởi các yêu cầu trong không gian vấn đề (ví dụ: Mẫu lệnh để hỗ trợ hoàn tác / làm lại, Chiến lược để hỗ trợ nhiều loại tệp đầu vào / đầu ra).

Nhiều mẫu xuất phát từ nhu cầu hỗ trợ các biến thể của phần mềm trong tương lai. Nếu bạn không bao giờ cần thực hiện các biến thể đó, một mẫu có thể được thiết kế quá mức. Một ví dụ sẽ sử dụng mẫu Adaptor để làm việc với cơ sở dữ liệu nhân sự bên ngoài hiện có. Bạn quyết định áp dụng Adaptor vì cơ sở dữ liệu hiện tại hoạt động với Oracle và bạn có thể muốn hỗ trợ NoQuery trong tương lai. Nếu NoQuery không bao giờ đến với tổ chức của bạn, mã Adaptor đó rất có thể là vô dụng. Xem YAGNI . Hỗ trợ cho các biến thể không bao giờ đến là lạm dụng một mẫu thiết kế.


0

Các mẫu là giải pháp phổ biến cho các vấn đề phổ biến. Chúng tôi luôn theo dõi một số mẫu, các mẫu theo địa chỉ GoF là các mẫu định kỳ nhất. Điều đó, để có một sự hiểu biết chung và cách tiếp cận được chia sẻ cho các kỹ sư phần mềm.

Điều đó nói rằng, câu trả lời của tôi là không, nhưng vâng, bạn luôn theo một số mô hình của riêng bạn. Như GoF đã đặt đúng

Mẫu của một người là khối xây dựng nguyên thủy của người khác.

Trích dẫn hay.


điều này dường như không cung cấp bất cứ điều gì đáng kể qua các điểm được thực hiện và giải thích trong 7 câu trả lời trước
gnat

Khỏe. Lưu ý, tôi đã đưa ra một điểm chung ... nó có thể áp dụng cho Mẫu thiết kế như một cuộc thảo luận lý thuyết.
Syed Priom

"Trang web này là tất cả về việc nhận câu trả lời . Đây không phải là một diễn đàn thảo luận ..." ( tham quan )
gnat

Tôi đã trả lời câu hỏi. Cảm ơn bạn. Cuộc trò chuyện này kết thúc tại đây.
Syed Priom

@gnat đó là một cái quái gì đó súc tích hơn rất nhiều, mặc dù.
djechlin

0

Khi tôi viết mã, tôi không có kế hoạch cố tình sử dụng nhiều mẫu thiết kế nhất có thể. Nhưng, tôi đoán, một cách có ý thức, khi tôi gặp vấn đề về mã hóa, một trong những mẫu thiết kế có vẻ phù hợp, và tôi chỉ sử dụng nó. Và đôi khi không có gì phù hợp. Điều quan trọng hơn với tôi là viết mã thực hiện công việc và dễ dàng duy trì và phát triển.

Dưới đây là một bài viết về việc áp dụng các nguyên tắc của 3M bằng cách sử dụng các mẫu thiết kế và nó cũng có các ví dụ mã (trong C ++). Nó cho thấy cách thức và thời điểm áp dụng một số mẫu thiết kế để viết mã sạch.


2
Bài báo đó đã được viết vào ngày hôm qua; bạn có liên kết với blog không? Nếu vậy, xin vui lòng tiết lộ liên kết đó .
Martijn Pieters
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.