Nguyên tắc ít kiến ​​thức nhất


32

Tôi hiểu động cơ đằng sau nguyên tắc ít kiến ​​thức nhất , nhưng tôi thấy một số nhược điểm nếu tôi cố gắng áp dụng nó trong thiết kế của mình.

Một trong những ví dụ của nguyên tắc này (thực ra là không sử dụng nó như thế nào), mà tôi đã tìm thấy trong cuốn sách Head First Design Forms xác định rằng việc gọi một phương thức trên các đối tượng được trả về từ các phương thức khác là sai, theo nguyên tắc này .

Nhưng dường như đôi khi rất cần sử dụng khả năng như vậy.

Ví dụ: Tôi có một số lớp: lớp quay video, lớp mã hóa, lớp streamer và tất cả chúng đều sử dụng một số lớp cơ bản khác, VideoFrame và vì chúng tương tác với nhau, nên chúng có thể làm ví dụ như thế này:

streamer mã lớp

...
frame = encoder->WaitEncoderFrame()
frame->DoOrGetSomething();
....

Như bạn có thể thấy, nguyên tắc này không được áp dụng ở đây. Nguyên tắc này có thể được áp dụng ở đây không, hay nguyên tắc này không thể luôn luôn được áp dụng trong một thiết kế như thế này?


trùng lặp có thể có của Phương thức xích và đóng gói
gnat


4
Đó có lẽ là một bản sao gần gũi hơn.
Robert Harvey

Câu trả lời:


21

Nguyên tắc mà bạn đang nói đến (hay còn gọi là Law of Demeter ) cho các chức năng có thể được áp dụng bằng cách thêm một phương thức trợ giúp khác vào lớp streamer của bạn như

  {
    frame = encoder->WaitEncoderFrame()
    DoOrGetSomethingForFrame(frame); 
    ...
  }

  void DoOrGetSomethingForFrame(Frame *frame)
  {
     frame->DoOrGetSomething();
  }  

Bây giờ, mỗi chức năng chỉ "nói chuyện với bạn bè", không nói với "bạn của bạn bè".

IMHO nó là một hướng dẫn sơ bộ có thể giúp tạo ra các phương pháp tuân thủ nghiêm ngặt hơn nguyên tắc trách nhiệm duy nhất. Trong một trường hợp đơn giản như ở trên, có lẽ rất có ý kiến ​​nếu điều này thực sự đáng phiền phức và nếu mã kết quả thực sự "sạch" hơn, hoặc nếu nó sẽ chỉ mở rộng mã của bạn một cách chính thức mà không có bất kỳ lợi ích đáng chú ý nào.


Cách tiếp cận này có ưu điểm là làm cho việc kiểm tra đơn vị, gỡ lỗi và lý do về mã của bạn dễ dàng hơn nhiều.
gntskn

+1. Mặc dù, có một lý do rất chính đáng để không làm thay đổi mã đó là giao diện lớp có thể trở nên cồng kềnh với các phương thức mà công việc chỉ đơn thuần là thực hiện một hoặc một vài cuộc gọi thành một số phương thức khác (và không có logic bổ sung). Trong một số loại môi trường lập trình, giả sử C ++ COM (đáng chú ý là WIC và DirectX), có chi phí cao liên quan đến việc bổ sung từng phương thức duy nhất vào giao diện COM, so với các ngôn ngữ khác.
rwong

1
Trong thiết kế giao diện COM C ++, phân tách các lớp lớn thành các lớp nhỏ (có nghĩa là bạn có cơ hội nói chuyện với nhiều đối tượng cao hơn) và giảm thiểu số lượng phương thức giao diện là hai mục tiêu thiết kế với lợi ích thực sự (giảm chi phí) dựa trên hiểu biết sâu sắc của các cơ chế bên trong (bảng ảo, tái sử dụng mã, nhiều thứ khác). Do đó, các lập trình viên C ++ COM thường phải bỏ qua LoD.
rwong

10
+1: Luật của Demeter thực sự nên được đặt tên là Gợi ý của Demeter: YMMV
Kẻ lừa đảo nhị phân

Luật của demeter là một lời khuyên cho việc lựa chọn kiến ​​trúc, trong khi bạn đề nghị thay đổi mỹ phẩm để có vẻ như bạn tuân thủ 'luật' đó. Đó sẽ là một quan niệm sai lầm, bởi vì một sự thay đổi cú pháp không có nghĩa là đột nhiên mọi thứ đều ổn. Theo như tôi biết thì luật demeter về cơ bản có nghĩa là: nếu bạn muốn làm OOP, thì hãy dừng viết mã sản phẩm với các hàm getter ở mọi nơi.
dùng2180613

39

Nguyên tắc ít kiến ​​thức nhất hoặc Luật Demeter là một cảnh báo chống lại sự vướng víu của lớp bạn với các chi tiết của các lớp khác đi qua lớp này qua lớp khác. Nó nói với bạn rằng tốt hơn là chỉ nói chuyện với "bạn bè" của bạn chứ không phải với "bạn của bạn bè".

Hãy tưởng tượng bạn đã được yêu cầu hàn một tấm khiên lên bức tượng hiệp sĩ trong bộ áo giáp sáng bóng. Bạn cẩn thận đặt tấm khiên trên cánh tay trái để nó trông thật tự nhiên. Bạn nhận thấy có ba vị trí nhỏ trên cẳng tay, khuỷu tay và cánh tay trên nơi lá chắn xảy ra để chạm vào áo giáp. Bạn hàn cả ba nơi vì bạn muốn chắc chắn kết nối mạnh. Bây giờ hãy tưởng tượng ông chủ của bạn đang nổi điên vì anh ta không thể di chuyển khuỷu tay của bộ giáp. Bạn cho rằng áo giáp sẽ không bao giờ di chuyển và do đó đã tạo ra một kết nối bất động giữa cẳng tay và cánh tay trên. Chiếc khiên chỉ nên kết nối với bạn, cẳng tay. Không để cẳng tay bạn bè. Ngay cả khi bạn phải thêm một miếng kim loại để làm cho chúng chạm vào.

Phép ẩn dụ là tốt đẹp nhưng chúng ta thực sự có ý nghĩa gì bởi bạn bè? Bất cứ điều gì một đối tượng biết cách tạo hoặc tìm là một người bạn. Ngoài ra, một đối tượng chỉ có thể yêu cầu được trao các đối tượng khác , trong đó nó chỉ biết giao diện. Những người này không được tính là bạn bè vì không mong đợi làm thế nào để có được họ. Nếu đối tượng không biết họ đến từ đâu vì một thứ khác đã qua / tiêm thì đó không phải là bạn của một người bạn, thậm chí đó không phải là bạn. Đó là thứ mà đối tượng chỉ biết sử dụng. Đó là một điều tốt.

Khi cố gắng áp dụng các nguyên tắc như thế này, điều quan trọng là phải hiểu rằng họ không bao giờ cấm bạn hoàn thành điều gì đó. Chúng là một cảnh báo rằng bạn có thể bỏ qua việc thực hiện nhiều công việc hơn để đạt được một thiết kế tốt hơn hoàn thành điều tương tự.

Không ai muốn làm việc mà không có lý do, vì vậy điều quan trọng là phải hiểu những gì bạn đang thoát khỏi việc này. Trong trường hợp này, nó giữ cho mã của bạn linh hoạt. Bạn có thể thực hiện các thay đổi và có ít lớp khác bị ảnh hưởng bởi những thay đổi cần lo lắng. Điều đó nghe có vẻ tốt nhưng không giúp bạn quyết định phải làm gì trừ khi bạn coi đó là một loại giáo lý tôn giáo.

Thay vì mù quáng tuân theo nguyên tắc này, hãy dùng một phiên bản đơn giản của vấn đề này. Viết một giải pháp không theo nguyên tắc và một giải pháp đó. Bây giờ bạn có hai giải pháp bạn có thể so sánh mức độ dễ tiếp nhận của từng thay đổi bằng cách cố gắng thực hiện chúng trong cả hai.

Nếu bạn KHÔNG thể giải quyết vấn đề trong khi tuân theo nguyên tắc này, có khả năng bạn sẽ thiếu một kỹ năng khác.

Một giải pháp cho vấn đề cụ thể của bạn là đưa framevào một thứ gì đó (một lớp hoặc phương thức) biết cách nói chuyện với các khung để bạn không phải truyền bá tất cả các chi tiết trò chuyện trong khung đó, giờ chỉ biết cách và thời điểm lấy khung

Điều đó thực sự tuân theo một nguyên tắc khác: Sử dụng riêng biệt từ xây dựng.

frame = encoder->WaitEncoderFrame()

Bằng cách sử dụng mã này, bạn đã chịu trách nhiệm bằng cách nào đó có được a Frame. Bạn chưa nhận bất kỳ trách nhiệm nào khi nói chuyện với a Frame.

frame->DoOrGetSomething(); 

Bây giờ bạn phải biết cách nói chuyện với a Frame, nhưng thay thế bằng:

new FrameHandler(frame)->DoOrGetSomething();

Và bây giờ bạn chỉ cần biết cách nói chuyện với bạn của mình, FrameHandler.

Có nhiều cách để đạt được điều này và có lẽ, đây không phải là cách tốt nhất nhưng nó cho thấy làm thế nào theo nguyên tắc không làm cho vấn đề không thể giải quyết được. Nó chỉ đòi hỏi nhiều công việc hơn từ bạn.

Mỗi quy tắc tốt đều có một ngoại lệ. Ví dụ tốt nhất tôi biết là ngôn ngữ cụ thể miền nội bộ . Một DSL của chuỗi phương phápdường như lạm dụng Luật Demeter mọi lúc vì bạn liên tục gọi các phương thức trả về các loại khác nhau và sử dụng chúng trực tiếp. Tại sao điều này là OK? Bởi vì trong DSL, mọi thứ được trả về là một người bạn được thiết kế cẩn thận mà bạn muốn nói chuyện trực tiếp. Theo thiết kế, bạn đã được trao quyền mong muốn chuỗi phương thức của DSL không thay đổi. Bạn không có quyền đó nếu bạn chỉ ngẫu nhiên đi sâu vào cơ sở mã kết nối với nhau bất cứ điều gì bạn tìm thấy. Các DSL tốt nhất là các biểu diễn hoặc giao diện rất mỏng cho các đối tượng khác mà bạn có thể không nên đi sâu vào một trong hai. Tôi chỉ đề cập đến điều này bởi vì tôi thấy tôi hiểu luật của demeter tốt hơn nhiều khi tôi biết tại sao DSL là một thiết kế tốt. Một số người đi xa đến mức nói rằng DSL thậm chí không vi phạm luật pháp thực sự của demeter.

Một giải pháp khác là để cho một cái gì đó khác tiêm framevào bạn. Nếu frameđến từ một setter hoặc tốt nhất là một constructor thì bạn không chịu bất kỳ trách nhiệm nào trong việc xây dựng hoặc có được một khung. Điều này có nghĩa là vai trò của bạn ở đây giống như FrameHandlerssẽ xảy ra hơn. Thay vào đó, bây giờ bạn là người hay nói chuyện Framevà làm một cái gì đó khác để tìm ra cách để có được Frame Theo cách này, đây là giải pháp tương tự với một sự thay đổi quan điểm đơn giản.

Các nguyên tắc RẮN là những nguyên tắc lớn mà tôi cố gắng tuân theo. Hai được tôn trọng ở đây là Nguyên tắc đảo ngược trách nhiệm và phụ thuộc duy nhất. Thật sự rất khó để tôn trọng hai người này và cuối cùng vẫn vi phạm Luật Demeter.

Tâm lý đi vào vi phạm Demeter giống như ăn tại một nhà hàng tự chọn, nơi bạn chỉ cần lấy bất cứ thứ gì bạn muốn. Với một chút công việc trả trước, bạn có thể cung cấp cho mình một menu và một máy chủ sẽ mang đến cho bạn bất cứ thứ gì bạn thích. Ngồi lại, thư giãn, và tip tốt.


2
"Nó nói với bạn rằng tốt hơn là chỉ nói chuyện với" bạn bè "của bạn chứ không phải với" bạn của bạn bè "" ++
RubberDuck

1
Đoạn thứ hai, bị đánh cắp từ đâu đó, hoặc bạn đã làm cho nó lên? Điều đó khiến tôi hiểu khái niệm hoàn toàn . Nó làm cho nó trở nên trắng trợn với "bạn của bạn bè" là gì, và những hạn chế của việc vướng vào quá nhiều lớp học (khớp). Một trích dẫn +.
chết

2
@diemaus Nếu tôi lấy trộm đoạn khiên đó từ đâu đó thì nguồn đó đã bị rò rỉ ra khỏi đầu tôi. Lúc đó não tôi chỉ nghĩ nó thông minh. Những gì tôi nhớ là tôi đã thêm nó sau nhiều lần nâng cấp vì vậy thật tuyệt khi thấy nó được xác nhận. Vui vì nó đã giúp.
candied_orange

19

Là thiết kế chức năng tốt hơn so với thiết kế hướng đối tượng? Nó phụ thuộc.

MVVM có tốt hơn MVC không? Nó phụ thuộc.

Amos & Andy hay Martin và Lewis? Nó phụ thuộc.

Nó phụ thuộc vào cái gì? Các lựa chọn bạn đưa ra phụ thuộc vào mức độ mỗi kỹ thuật hoặc công nghệ đáp ứng các yêu cầu chức năng và phi chức năng của phần mềm của bạn, trong khi đáp ứng đầy đủ các mục tiêu về thiết kế, hiệu suất và khả năng bảo trì của bạn.

[Một số cuốn sách] nói rằng [một số điều] là sai.

Khi bạn đọc điều này trong một cuốn sách hoặc blog, hãy đánh giá yêu cầu dựa trên giá trị của nó; đó là hỏi tại sao Không có kỹ thuật đúng hay sai trong phát triển phần mềm, chỉ có "kỹ thuật này đáp ứng mục tiêu của tôi tốt như thế nào? Nó có hiệu quả hay không hiệu quả? Nó có giải quyết được một vấn đề nhưng tạo ra một vấn đề mới không? nhóm phát triển, hay nó quá tối nghĩa? "

Trong trường hợp cụ thể này - hành động gọi một phương thức trên một đối tượng được trả về bởi một phương thức khác - vì có một mẫu thiết kế thực tế mã hóa thực tiễn này (Factory), thật khó để tưởng tượng làm thế nào người ta có thể đưa ra khẳng định rằng nó là phân loại sai rồi.

Lý do nó được gọi là "Nguyên tắc tối thiểu của kiến ​​thức" là "Khớp nối thấp" là một chất lượng mong muốn của một hệ thống. Các đối tượng không bị ràng buộc chặt chẽ với nhau hoạt động độc lập hơn và do đó dễ dàng hơn để duy trì và sửa đổi riêng lẻ. Nhưng như ví dụ của bạn cho thấy, có những thời điểm mà tính khớp nối cao được mong muốn hơn, để các đối tượng có thể phối hợp hiệu quả hơn với những nỗ lực của họ.


2

Câu trả lời của Doc Brown cho thấy một triển khai sách giáo khoa cổ điển của Law of Demeter - và sự phiền toái / vô tổ chức của việc thêm hàng tá phương pháp có lẽ là lý do tại sao các lập trình viên, bao gồm cả tôi, thường không bận tâm làm điều đó, ngay cả khi họ nên làm.

Có một cách khác để tách rời cấu trúc phân cấp của các đối tượng:

Vạch trần interfacecác loại, chứ không phải classcác loại, thông qua phương pháp và tài sản của bạn.

Trong trường hợp của Poster gốc (OP), encoder->WaitEncoderFrame()sẽ trả về IEncoderFramethay vì Framevà sẽ xác định thao tác nào được phép.


GIẢI PHÁP 1

Trong trường hợp dễ nhất FrameEncodercác lớp đều nằm dưới sự kiểm soát của bạn, IEncoderFramelà một tập hợp con các phương thức Khung đã được hiển thị công khai và Encoderlớp không thực sự quan tâm bạn làm gì với đối tượng đó. Sau đó, việc thực hiện là không đáng kể ( mã trong c # ):

interface IEncoderFrame {
    void DoOrGetSomething();
}

class Frame : IEncoderFrame {
    // A method that already exists in Frame.
    public void DoOrGetSomething() { ... }
}

class Encoder {
    private Frame _frame;
    public IEncoderFrame TheFrame { get { return _frame; } }
    ...
}

GIẢI PHÁP 2

Trong trường hợp trung gian, trong đó Frameđịnh nghĩa không nằm trong tầm kiểm soát của bạn hoặc không phù hợp để thêm IEncoderFramephương thức vào Frame, thì một giải pháp tốt là Bộ điều hợp . Đó là những gì câu trả lời của CandiedOrange thảo luận, như new FrameHandler( frame ). QUAN TRỌNG: Nếu bạn làm điều này, nó sẽ linh hoạt hơn nếu bạn trưng bày nó dưới dạng giao diện , không phải là một lớp . Encoderphải biết về class FrameHandler, nhưng khách hàng chỉ cần biết interface IFrameHandler. Hoặc như tôi đã đặt tên cho nó, interface IEncoderFrame- để chỉ ra rằng đó là Khung cụ thể như được thấy từ POV của Encoder :

interface IEncoderFrame {
    void DoOrGetSomething();
}

// Adapter pattern. Appropriate if no access needed to Encoder.
class EncoderFrameWrapper : IEncoderFrame {
    Frame _frame;
    public EncoderFrameWrapper( Frame frame ) {
        _frame = frame;
    }
    public void DoOrGetSomething() {
        _frame....;
    }
}

class Encoder {
    private Frame _frame;

    // Adapter pattern. Appropriate if no access needed to Encoder.
    public IEncoderFrame TheFrame { get { return new EncoderFrameWrapper( _frame ); } }

    ...
}

CHI PHÍ: Phân bổ và GC của một đối tượng mới, EncoderFrameWrapper, mỗi lần encoder.TheFrameđược gọi. (Bạn có thể lưu trữ trình bao bọc đó, nhưng điều đó thêm nhiều mã hơn. Và chỉ dễ mã hóa một cách đáng tin cậy nếu trường khung của bộ mã hóa không thể được thay thế bằng một khung mới.)


GIẢI PHÁP 3

Trong trường hợp khó khăn hơn, trình bao bọc mới sẽ cần biết về cả hai EncoderFrame. Bản thân đối tượng đó sẽ vi phạm LoD - nó đang thao túng mối quan hệ giữa Encoder và Frame nên là trách nhiệm của Encoder - và có lẽ là một nỗi đau để có được quyền. Đây là những gì có thể xảy ra nếu bạn bắt đầu con đường đó:

interface IEncoderFrame {
    void DoOrGetSomething();
}

// *** You will end up regretting this. See next code snippet instead ***
class EncoderFrameWrapper : IEncoderFrame {
    Encoder _owner;
    Frame _frame;
    public EncoderFrameWrapper( Encoder owner, Frame frame ) {
        _owner = owner;   _frame = frame;
    }
    public void DoOrGetSomething() {
        _frame.DoOrGetSomething();
        // Hmm, maybe this wrapper class should be nested inside Encoder...
        _owner... some work inside owner; maybe should be owner-internal details ...
    }
}

class Encoder {
    private Frame _frame;

    ...
}

Điều đó trở nên xấu xí. Có một triển khai ít phức tạp hơn, khi trình bao bọc cần chạm vào chi tiết của người tạo / chủ sở hữu của nó (Bộ mã hóa):

interface IEncoderFrame {
    void DoOrGetSomething();
}

class Encoder : IEncoderFrame {
    private Frame _frame;

    // HA! Client gets to think of this as "the frame object",
    // but its really me, intercepting it.
    public IEncoderFrame TheFrame { get { return this; } }

    // This is the method that the LoD approach suggests writing,
    // except that we are exposing it only when the instance is accessed as an IEncoderFrame,
    // to avoid extending Encoder's already large API surface.
    public void IEncoderFrame.DoOrGetSomething() {
        _frame.DoOrGetSomething();
       ... make some change within current Encoder instance ...
    }
    ...
}

Cấp, nếu tôi biết tôi sẽ kết thúc ở đây, tôi có thể không làm điều này. Chỉ có thể viết các phương thức LoD, và được thực hiện với nó. Không cần xác định một giao diện. Mặt khác, tôi thích rằng giao diện kết hợp các phương thức liên quan với nhau. Tôi thích cảm giác khi thực hiện "các thao tác giống như khung" với cảm giác giống như một khung.


Ý KIẾN CUỐI CÙNG

Hãy xem xét điều này: Nếu người triển khai Encodercảm thấy rằng việc phơi bày Frame framephù hợp với kiến ​​trúc tổng thể của họ hoặc "dễ dàng hơn nhiều so với thực hiện LoD", thì sẽ an toàn hơn nhiều nếu họ thay vào đó là đoạn trích đầu tiên tôi trình bày - phơi bày một tập hợp con giới hạn của Khung, như một giao diện. Theo kinh nghiệm của tôi, đó thường là một giải pháp hoàn toàn khả thi. Chỉ cần thêm phương thức vào giao diện khi cần thiết. (Tôi đang nói về một kịch bản mà chúng ta "biết" Khung đã có các phương thức cần thiết hoặc chúng sẽ dễ dàng và không gây tranh cãi để thêm vào. Công việc "triển khai" cho mỗi phương thức là thêm một dòng vào định nghĩa giao diện.) Và biết rằng ngay cả trong trường hợp xấu nhất trong tương lai, vẫn có thể giữ API đó hoạt động - tại đây,IEncoderFrameFrameEncoder.

Cũng lưu ý rằng nếu bạn không có quyền thêm IEncoderFramevào Framehoặc các phương thức cần thiết không phù hợp với Framelớp chung và giải pháp số 2 không phù hợp với bạn, có lẽ do việc tạo và hủy đối tượng thêm, giải pháp số 3 có thể được xem đơn giản là một cách để tổ chức các phương pháp Encoder, để thực hiện LoD. Đừng chỉ thông qua hàng tá phương pháp. Gói chúng trong một Giao diện và sử dụng "triển khai giao diện rõ ràng" (nếu bạn ở c #), để chúng chỉ có thể được truy cập khi đối tượng được xem qua giao diện đó.

Một điểm khác tôi muốn nhấn mạnh là quyết định phơi bày chức năng như một giao diện , xử lý cả 3 tình huống được mô tả ở trên. Đầu tiên, IEncoderFramechỉ đơn giản là một tập hợp con của Framechức năng. Trong thứ hai, IEncoderFramelà một bộ chuyển đổi. Trong phần ba, IEncoderFramelà một phân vùng thành Encoderchức năng s. Sẽ không có vấn đề gì nếu nhu cầu của bạn thay đổi giữa ba tình huống này: API vẫn giữ nguyên.


Ghép lớp của bạn với một giao diện được trả về bởi một trong những cộng tác viên của nó, chứ không phải là một lớp cụ thể, trong khi một cải tiến, vẫn là một nguồn của khớp nối. Nếu giao diện cần thay đổi, điều đó có nghĩa là lớp của bạn sẽ cần thay đổi. Điểm quan trọng cần bỏ đi là khớp nối vốn dĩ không tệ, miễn là bạn chắc chắn rằng bạn tránh được cặp đôi không cần thiết với các vật thể không ổn định hoặc cấu trúc bên trong . Đây là lý do tại sao Luật Demeter cần phải được thực hiện với một nhúm muối lớn; nó hướng dẫn bạn luôn luôn tránh một cái gì đó có thể hoặc không phải là một vấn đề, tùy thuộc vào hoàn cảnh.
Periata Breatta

@PeriataBreatta - Tôi chắc chắn không thể và không đồng ý với điều đó. Nhưng tôi muốn chỉ ra một điều: Giao diện , theo định nghĩa, đại diện cho những gì cần được biết ở ranh giới giữa hai lớp. Nếu nó "cần phải thay đổi", đó là điều cơ bản - không có cách tiếp cận nào khác có thể tránh được một cách kỳ diệu mã hóa cần thiết. Ngược lại với việc thực hiện bất kỳ tình huống nào trong ba tình huống tôi mô tả, nhưng không sử dụng giao diện - thay vào đó, trả về một lớp cụ thể. Trong 1, Khung, trong 2, EncoderFrameWrapper, trong 3, Encoder. Bạn tự khóa mình vào cách tiếp cận đó . Giao diện có thể thích ứng với tất cả chúng.
ToolmakerSteve

@PeriataBreatta ... thể hiện lợi ích của việc xác định rõ ràng nó là một giao diện. Tôi hy vọng cuối cùng sẽ tăng cường một IDE để làm cho nó thuận tiện, các giao diện đó sẽ được sử dụng nhiều hơn nữa. Hầu hết các truy cập đa cấp sẽ thông qua một số giao diện, do đó dễ dàng hơn nhiều để quản lý các thay đổi. (Nếu đó là "quá mức" đối với một số trường hợp, phân tích mã, kết hợp với chú thích về nơi chúng tôi sẵn sàng chấp nhận rủi ro không có giao diện, để đổi lấy việc tăng hiệu suất nhỏ, có thể "biên dịch nó" một trong 3 lớp cụ thể trong 3 "giải pháp".)
ToolmakerSteve

@PeriataBreatta - và khi tôi nói "giao diện có thể thích ứng với tất cả chúng", tôi không nói "ahhhh, thật tuyệt vời khi tính năng một ngôn ngữ này có thể bao gồm các trường hợp khác nhau này". Tôi đang nói rằng việc xác định giao diện sẽ giảm thiểu những thay đổi bạn có thể cần thực hiện. Trong trường hợp tốt nhất, thiết kế có thể thay đổi tất cả từ trường hợp đơn giản nhất (giải pháp 1), sang trường hợp khó khăn nhất (giải pháp 3), mà không thay đổi giao diện - chỉ có nhu cầu nội bộ của nhà sản xuất trở nên phức tạp hơn. Và ngay cả khi cần thay đổi, chúng có xu hướng ít phổ biến hơn, IMHO.
ToolmakerSteve
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.