RẮN so với các phương thức tĩnh


11

Đây là một vấn đề tôi thường gặp phải: Hãy có một dự án cửa hàng web có lớp Sản phẩm. Tôi muốn thêm một tính năng cho phép người dùng đăng đánh giá lên sản phẩm. Vì vậy, tôi có một lớp Đánh giá tham khảo một sản phẩm. Bây giờ tôi cần một phương pháp liệt kê tất cả các đánh giá cho một sản phẩm. Có hai khả năng:

(A)

public class Product {
  ...
  public Collection<Review> getReviews() {...}
}

(B)

public class Review {
  ...
  static public Collection<Review> forProduct( Product product ) {...}
}

Từ việc xem mã, tôi chọn (A): Nó không tĩnh và không cần tham số. Tuy nhiên, tôi cảm thấy rằng (A) vi phạm Nguyên tắc Trách nhiệm Đơn lẻ (SRP) và Nguyên tắc Đóng mở (OCP) trong khi (B) không:

  • (SRP) Khi tôi muốn thay đổi cách thu thập đánh giá cho một sản phẩm, tôi phải thay đổi lớp Sản phẩm. Nhưng chỉ nên có một lý do để thay đổi lớp Sản phẩm. Và đó chắc chắn không phải là đánh giá. Nếu tôi đóng gói mọi tính năng có liên quan đến sản phẩm trong Sản phẩm, nó sẽ sớm bị hỏng.

  • (OCP) Tôi phải thay đổi lớp Sản phẩm để mở rộng nó với tính năng này. Tôi nghĩ rằng điều này vi phạm phần 'Đóng để thay đổi' của nguyên tắc. Trước khi tôi nhận được yêu cầu của khách hàng về việc thực hiện đánh giá, tôi đã coi Sản phẩm là hoàn thành và "đóng" nó.

Điều gì quan trọng hơn: tuân theo các nguyên tắc RẮN hoặc có giao diện đơn giản hơn?

Hay tôi đang làm gì đó sai ở đây hoàn toàn?

Kết quả

Wow, cảm ơn vì tất cả các câu trả lời tuyệt vời của bạn! Thật khó để chọn một câu trả lời chính thức.

Hãy để tôi tóm tắt các đối số chính từ các câu trả lời:

  • pro (A): OCP không phải là luật và khả năng đọc mã cũng rất quan trọng.
  • pro (A): mối quan hệ thực thể nên được điều hướng. Cả hai lớp có thể biết về mối quan hệ này.
  • pro (A) + (B): thực hiện cả hai và ủy nhiệm trong (A) đến (B) để Sản phẩm ít có khả năng được thay đổi lại.
  • pro (C): đặt các phương thức tìm kiếm vào lớp thứ ba (dịch vụ) trong đó nó không tĩnh.
  • contra (B): cản trở việc chế nhạo trong các bài kiểm tra.

Một vài điều nữa trường đại học của tôi tại nơi làm việc đã đóng góp:

  • pro (B): khung ORM của chúng tôi có thể tự động tạo mã cho (B).
  • pro (A): vì lý do kỹ thuật của khung ORM của chúng tôi, sẽ cần phải thay đổi thực thể "đóng" trong một số trường hợp, độc lập với nơi mà người tìm thấy đi đến. Vì vậy, dù sao tôi cũng sẽ không thể bám vào RẮN.
  • contra (C): to fuss ;-)

Phần kết luận

Tôi đang sử dụng cả (A) + (B) với ủy quyền cho dự án hiện tại của mình. Tuy nhiên, trong môi trường hướng dịch vụ, tôi sẽ sử dụng (C).


2
Miễn là nó không phải là một biến tĩnh, mọi thứ đều tuyệt. Phương pháp tĩnh đơn giản để kiểm tra và đơn giản để theo dõi.
Coder

3
Tại sao không chỉ có một lớp ProductsReview? Sau đó, Sản phẩm và Đánh giá giữ nguyên. Hoặc có thể tôi hiểu lầm.
ElGringoGrande

2
@Coder "Phương pháp tĩnh rất đơn giản để kiểm tra", thật sao? Họ không thể bị chế giễu, xem: googletesting.blogspot.com/2008/12/ trên để biết thêm chi tiết.
StuperUser 15/03 '

1
@StuperUser: Không có gì để chế giễu. Assert(5 = Math.Abs(-5));
Coder

2
Kiểm tra Abs()không phải là vấn đề, kiểm tra một cái gì đó phụ thuộc vào nó là. Bạn không có đường nối để cách ly Mã kiểm tra phụ thuộc (CUT) để sử dụng giả. Điều này có nghĩa là bạn không thể kiểm tra nó như một đơn vị nguyên tử và tất cả các bài kiểm tra của bạn trở thành kiểm tra tích hợp kiểm tra logic đơn vị. Thất bại trong xét nghiệm có thể ở CUT hoặc trong Abs()(hoặc mã phụ thuộc của nó) và loại bỏ các lợi ích chẩn đoán của các xét nghiệm đơn vị.
StuperUser 15/03 '

Câu trả lời:


7

Điều gì quan trọng hơn: tuân theo các nguyên tắc RẮN hoặc có giao diện đơn giản hơn?

Giao diện vis-a-vis RẮN

Đây không phải là loại trừ lẫn nhau. Giao diện nên thể hiện bản chất của mô hình kinh doanh của bạn một cách lý tưởng theo thuật ngữ mô hình kinh doanh. Các nguyên tắc RẮN là một Koan để tối đa hóa khả năng duy trì mã hướng đối tượng (và ý tôi là "khả năng duy trì" theo nghĩa rộng nhất). Cái trước hỗ trợ việc sử dụng và thao tác mô hình kinh doanh của bạn và cái sau tối ưu hóa bảo trì mã.

Nguyên tắc mở / đóng

"đừng chạm vào đó!" là một cách giải thích quá đơn giản. Và giả sử chúng tôi có nghĩa là "lớp" là tùy ý, và không nhất thiết phải đúng. Thay vào đó, OCP có nghĩa là bạn đã thiết kế mã của mình sao cho việc sửa đổi hành vi của nó không (không nên) yêu cầu bạn phải sửa đổi trực tiếp mã làm việc hiện có. Hơn nữa, không chạm vào mã ở nơi đầu tiên là cách lý tưởng để duy trì tính toàn vẹn của các giao diện hiện có; theo quan điểm của tôi, đây là một hệ quả quan trọng của OCP.

Cuối cùng tôi thấy OCP là một chỉ số về chất lượng thiết kế hiện có. Nếu tôi thấy mình bẻ khóa các lớp mở (hoặc phương thức) quá thường xuyên và / hoặc không có lý do thực sự (ha, ha) chắc chắn để làm như vậy thì điều này có thể nói với tôi rằng tôi có một thiết kế xấu (và / hoặc tôi không biết cách viết mã OO).

Hãy cho nó bức ảnh đẹp nhất của bạn, chúng tôi có một đội ngũ bác sĩ đứng bên cạnh

Nếu phân tích yêu cầu của bạn cho bạn biết rằng bạn cần thể hiện mối quan hệ Đánh giá sản phẩm từ cả hai quan điểm, thì hãy làm như vậy.

Do đó, Wolfgang, bạn có thể có một lý do chính đáng để sửa đổi các lớp hiện có. Đưa ra các yêu cầu mới, nếu Đánh giá hiện là một phần cơ bản của Sản phẩm, nếu mọi tiện ích mở rộng của Sản phẩm cần Đánh giá, nếu làm như vậy sẽ làm cho mã khách hàng có biểu cảm phù hợp, sau đó tích hợp nó vào Sản phẩm.


1
+1 để lưu ý rằng OCP là một chỉ số có chất lượng tốt, không phải là quy tắc nhanh cho bất kỳ mã nào. Nếu bạn thấy rằng khó theo hoặc không thể tuân thủ đúng OCP, thì đó là dấu hiệu mô hình của bạn cần được tái cấu trúc để cho phép tái sử dụng linh hoạt hơn.
CodexArcanum

Tôi đã chọn ví dụ về Sản phẩm và Đánh giá để chỉ ra rằng Sản phẩm là một thực thể cốt lõi của dự án trong khi Đánh giá chỉ là một tiện ích bổ sung. Vì vậy, Sản phẩm đã tồn tại, đã hoàn thành và Đánh giá đến sau và sẽ được giới thiệu mà không cần mở mã hiện tại (bao gồm Sản phẩm).
Wolfgang

10

RẮN là hướng dẫn, vì vậy ảnh hưởng đến việc ra quyết định thay vì ra lệnh.

Một điều cần lưu ý khi sử dụng các phương thức tĩnh là tác động của chúng đến khả năng kiểm tra .


Kiểm tra forProduct(Product product)sẽ không thành vấn đề.

Kiểm tra một cái gì đó phụ thuộc vào nó sẽ được.

Bạn sẽ không có đường nối để cô lập Mã kiểm tra dưới mã (CUT) phụ thuộc để sử dụng giả, vì khi ứng dụng đang chạy, các phương thức tĩnh nhất thiết phải tồn tại.

Chúng ta hãy có một phương thức gọi CUT()đó là các cuộc gọiforProduct()

Nếu forProduct()staticbạn không thể kiểm tra CUT()như một đơn vị nguyên tử và tất cả các bài kiểm tra của bạn trở nên kiểm tra tích hợp đơn vị kiểm tra logic.

Thất bại trong xét nghiệm CUT, có thể do sự cố trong CUT()hoặc trong forProduct()(hoặc bất kỳ mã phụ thuộc nào của nó), loại bỏ các lợi ích chẩn đoán của các xét nghiệm đơn vị.

Xem bài đăng blog tuyệt vời này để biết thêm thông tin chi tiết: http://googletesting.blogspot.com/2008/12/static-methods-are-death-to-testability.html


Điều này có thể dẫn đến sự thất vọng với các bài kiểm tra thất bại và từ bỏ các thực hành tốt và lợi ích xung quanh chúng.


1
Đó là một điểm rất tốt. Nói chung, không phải cho tôi mặc dù. ;-) Tôi không quá khắt khe về việc viết bài kiểm tra đơn vị bao gồm nhiều hơn một lớp. Tất cả đều đi xuống cơ sở dữ liệu, điều đó ổn đối với tôi. Vì vậy, tôi sẽ không chế nhạo đối tượng kinh doanh hoặc đó là công cụ tìm.
Wolfgang

+1, cảm ơn vì đã đặt cờ đỏ cho các bài kiểm tra! Tôi đồng ý với @Wolfgang, thường thì tôi cũng không quá nghiêm khắc nhưng khi tôi cần loại thử nghiệm đó, tôi thực sự ghét các phương pháp tĩnh. Thông thường nếu một phương thức tĩnh tương tác quá nhiều với các tham số của nó hoặc nếu tương tác với bất kỳ phương thức tĩnh nào khác, tôi thích biến nó thành một phương thức cá thể.
Adriano Repetti

Điều này không phụ thuộc hoàn toàn vào ngôn ngữ đang được sử dụng? OP đã sử dụng một ví dụ Java, nhưng không bao giờ đề cập đến một ngôn ngữ trong câu hỏi, cũng không phải là một ngôn ngữ được chỉ định trong các thẻ.
Izkata

1
@StuperUser If forProduct() is static you can't test CUT() as an atomic unit and all of your tests become integration tests that test unit logic.- Tôi tin rằng cả Javascript và Python đều cho phép các phương thức tĩnh bị ghi đè / chế nhạo. Tôi không chắc chắn 100%, mặc dù.
Izkata

1
@Izkata JS được gõ động, vì vậy không có static, bạn mô phỏng nó với một bao đóng và mẫu đơn. Đọc lên Python (đặc biệt là stackoverflow.com/questions/893015/ - ), bạn phải kế thừa và mở rộng. Ghi đè không chế nhạo; có vẻ như bạn vẫn chưa có đường may để kiểm tra mã dưới dạng đơn vị nguyên tử.
StuperUser 16/03 '

4

Nếu bạn nghĩ rằng Sản phẩm là nơi thích hợp để tìm Nhận xét của sản phẩm, bạn luôn có thể cung cấp cho Sản phẩm một lớp trợ giúp để thực hiện công việc cho sản phẩm đó. (Bạn có thể nói vì doanh nghiệp của bạn sẽ không bao giờ nói về đánh giá ngoại trừ về mặt sản phẩm).

Ví dụ, tôi sẽ bị cám dỗ tiêm thứ gì đó đóng vai trò của người truy xuất đánh giá. Tôi có thể sẽ cung cấp cho nó giao diện IRetrieveReviews. Bạn có thể đặt cái này trong hàm tạo của sản phẩm (Dependency Injection). Nếu bạn muốn thay đổi cách đánh giá được lấy ra, bạn có thể làm điều đó một cách dễ dàng bằng cách tiêm một cộng tác viên khác nhau - một TwitterReviewRetrieverhoặc một AmazonReviewRetrieverhoặc MultipleSourceReviewRetrieverhoặc bất cứ điều gì khác mà bạn cần.

Hiện tại cả hai đều có một trách nhiệm duy nhất (tương ứng với tất cả những thứ liên quan đến sản phẩm và truy xuất đánh giá), và trong tương lai, hành vi của sản phẩm đối với đánh giá có thể được sửa đổi mà không thực sự thay đổi sản phẩm (bạn có thể mở rộng sản phẩm như ProductWithReviewsthể bạn thực sự muốn trở thành nhà mô phạm về các nguyên tắc RẮN của mình, nhưng điều này sẽ đủ tốt cho tôi).


Âm thanh giống như mẫu DAO rất phổ biến trong phần mềm hướng dịch vụ / thành phần. Tôi thích ý tưởng này vì nó thể hiện rằng việc lấy các đối tượng không phải là trách nhiệm của các đối tượng này. Tuy nhiên, vì tôi thích một cách hướng đối tượng hơn là hướng dịch vụ.
Wolfgang

1
Sử dụng một giao diện như IRetrieveReviewsdừng nó theo hướng dịch vụ - nó không xác định cái gì nhận được đánh giá, hoặc làm thế nào hoặc khi nào. Có lẽ đó là một dịch vụ với nhiều phương pháp cho những thứ như thế này. Có lẽ đó là một lớp học làm điều đó. Có thể đó là kho lưu trữ hoặc yêu cầu HTTP đến máy chủ. Bạn không biết. Bạn không nên biết. Đó là điểm.
Lunivore

Vâng, vì vậy nó sẽ là một triển khai của mô hình chiến lược. Đó sẽ là một đối số cho một lớp thứ ba. (A) và (B) sẽ không hỗ trợ điều này. Công cụ tìm chắc chắn sẽ sử dụng ORM, vì vậy không có lý do gì để thay thế thuật toán. Xin lỗi nếu tôi không rõ về điều này trong câu hỏi của tôi.
Wolfgang

3

Tôi sẽ có một lớp ProductsReview. Bạn nói Đánh giá là mới dù sao. Điều đó không có nghĩa là nó có thể là bất cứ điều gì. Nó vẫn phải có một lý do duy nhất để thay đổi. Nếu bạn thay đổi cách bạn nhận được các đánh giá vì bất kỳ lý do gì bạn sẽ phải thay đổi lớp Đánh giá.

Điều đó không chính xác.

Bạn đang đặt phương thức tĩnh trong lớp Xem lại vì ... tại sao? Đó không phải là những gì bạn đang đấu tranh với? Đó không phải là toàn bộ vấn đề sao?

Vậy thì đừng. Làm cho một lớp mà trách nhiệm duy nhất là nhận được các đánh giá sản phẩm. Sau đó, bạn có thể phân lớp nó thành ProductReviewByStartRating bất cứ điều gì. Hoặc phân lớp nó để nhận đánh giá cho một lớp sản phẩm.


Tôi không đồng ý rằng phương pháp Đánh giá sẽ vi phạm SRP. Trên sản phẩm, nó sẽ nhưng không đánh giá. Vấn đề của tôi là nó tĩnh. Nếu tôi di chuyển phương thức sang một lớp thứ ba, nó sẽ vẫn tĩnh và có tham số sản phẩm.
Wolfgang

Vì vậy, bạn đang nói rằng trách nhiệm duy nhất cho lớp Đánh giá, lý do duy nhất để nó thay đổi, là nếu phương thức tĩnh for sản phẩm cần thay đổi? Không có chức năng nào khác trong lớp Đánh giá?
ElGringoGrande

Có rất nhiều thứ trên Đánh giá. Nhưng tôi nghĩ rằng một Sản phẩm (Sản phẩm) sẽ phù hợp với nó. Tìm kiếm Đánh giá phụ thuộc rất nhiều vào các thuộc tính và cấu trúc của Đánh giá (định danh duy nhất, phạm vi thay đổi thuộc tính nào?). Tuy nhiên, Sản phẩm không biết và không nên biết về Nhận xét.
Wolfgang

3

Tôi sẽ không đặt chức năng 'Nhận đánh giá cho sản phẩm' trong cả Productlớp hoặc Reviewlớp ...

Bạn có một nơi mà bạn lấy Sản phẩm của mình, phải không? Một cái gì đó với GetProductById(int productId)và có thể GetProductsByCategory(int categoryId)và như vậy.

Tương tự như vậy, bạn nên có một nơi để lấy Nhận xét của mình, với a GetReviewbyId(int reviewId)và có thể a GetReviewsForProduct(int productId).

Khi tôi muốn thay đổi cách thu thập đánh giá cho một sản phẩm, tôi phải thay đổi lớp Sản phẩm.

Nếu bạn tách quyền truy cập dữ liệu của mình khỏi các lớp miền, bạn sẽ không cần thay đổi một trong hai lớp miền khi bạn thay đổi cách thu thập đánh giá.


Đây là cách tôi sẽ xử lý nó, và tôi bối rối (và lo lắng về việc liệu ý tưởng của riêng tôi có phù hợp không) bởi vì thiếu câu trả lời này cho đến khi bài viết của bạn. Rõ ràng không phải lớp đại diện cho một báo cáo cũng như đại diện của một sản phẩm phải chịu trách nhiệm cho việc thực sự lấy ra cái khác. Một số loại dịch vụ cung cấp dữ liệu nên được xử lý này.
CodexArcanum

@CodexArcanum Chà, bạn không đơn độc. :-)
Eric King

2

Các mô hình và nguyên tắc là hướng dẫn, không phải là quy tắc được viết trong đá. Trong tôi quan điểm câu hỏi không phải là nếu nó tốt hơn để làm theo nguyên tắc RẮN hoặc để giữ một giao diện đơn giản hơn. Những gì bạn nên tự hỏi mình là những gì dễ đọc và dễ hiểu hơn đối với hầu hết mọi người. Thông thường, điều này có nghĩa là nó phải càng gần với tên miền.

Trong trường hợp này, tôi thích giải pháp (B) hơn vì đối với tôi , điểm khởi đầu là Sản phẩm, không phải là Đánh giá mà hãy tưởng tượng bạn đang viết một phần mềm để quản lý đánh giá. Trong trường hợp đó, trung tâm là Đánh giá nên giải pháp (A) có thể thích hợp hơn.

Khi tôi có rất nhiều phương thức như thế này ("kết nối" giữa các lớp), tôi loại bỏ tất cả chúng ra bên ngoài và tôi tạo một (hoặc nhiều) lớp tĩnh mới để sắp xếp chúng. Thông thường bạn có thể xem chúng như các truy vấn hoặc loại kho lưu trữ.


Tôi cũng đã suy nghĩ về ý tưởng này về ngữ nghĩa của cả hai đầu và cái nào "mạnh hơn" nên nó sẽ yêu cầu người tìm thấy. Đó là lý do tại sao tôi nghĩ ra (B). Nó cũng sẽ giúp tạo ra một hệ thống phân cấp "trừu tượng" của các lớp kinh doanh. Sản phẩm là một đối tượng cơ bản đơn thuần trong đó Đánh giá là một đối tượng cao hơn. Vì vậy, Đánh giá có thể tham khảo Sản phẩm nhưng không phải là cách khác. Bằng cách này, các chu trình trong các tham chiếu giữa các lớp nghiệp vụ có thể tránh được, đó sẽ là một vấn đề khác trong danh sách của tôi được giải quyết.
Wolfgang

Tôi nghĩ rằng đối với một nhóm nhỏ các lớp, nó có thể tốt ngay cả khi cung cấp các phương thức BÓNG (A) và (B). Quá nhiều lần UI không được biết đến nhiều tại thời điểm viết logic này.
Adriano Repetti

1

Sản phẩm của bạn chỉ có thể ủy quyền cho phương pháp Đánh giá tĩnh của bạn, trong trường hợp đó bạn đang cung cấp giao diện thuận tiện ở vị trí tự nhiên (Product.getReview) nhưng chi tiết triển khai của bạn nằm trong Review.getForSản phẩm.

RẮN là hướng dẫn và sẽ dẫn đến một giao diện đơn giản, hợp lý. Ngoài ra, bạn có thể lấy được RẮN từ các giao diện đơn giản, hợp lý. Đó là tất cả về quản lý phụ thuộc trong mã. Mục tiêu là để giảm thiểu các phụ thuộc tạo ra ma sát và tạo ra rào cản đối với sự thay đổi không thể tránh khỏi.


Tôi không chắc chắn tôi sẽ muốn điều này. Theo cách này, tôi có phương pháp trên cả hai vị trí tốt vì các nhà phát triển khác không cần tìm trong cả hai lớp để xem nơi tôi đặt nó. Mặt khác, tôi sẽ có cả nhược điểm của phương thức tĩnh và thay đổi của lớp Sản phẩm "đã đóng". Tôi không chắc phái đoàn giúp thoát khỏi vấn đề ma sát. Nếu có một lý do để thay đổi công cụ tìm, chắc chắn điều đó sẽ dẫn đến việc thay đổi chữ ký và do đó lại thay đổi Sản phẩm.
Wolfgang

Chìa khóa của OCP là bạn có thể thay thế việc triển khai mà không thay đổi mã của mình. Trong thực tế, điều này được liên kết chặt chẽ với Thay thế Liskov. Một thực hiện phải được thay thế cho một thực hiện khác. Bạn có thể có DatabaseReview và SoapReview vì các lớp khác nhau đều triển khai IGetReview.getReview và getReviewFor Products. Sau đó, hệ thống của bạn là Mở để mở rộng (thay đổi cách nhận được đánh giá) và Đóng để sửa đổi (phụ thuộc vào IGetReview không bị phá vỡ). Đó là những gì tôi muốn nói bởi quản lý phụ thuộc. Trong trường hợp của bạn, bạn sẽ phải sửa đổi mã của mình để thay đổi hành vi của nó.
pfries

Không phải đó là Nguyên tắc đảo ngược phụ thuộc (DIP) mà bạn đang mô tả sao?
Wolfgang

Chúng là những nguyên tắc liên quan. Điểm thay thế của bạn đạt được bằng DIP.
pfries

1

Tôi có một chút khác biệt về điều này hơn hầu hết các câu trả lời khác. Tôi nghĩ rằng ProductReviewvề cơ bản là các đối tượng chuyển dữ liệu (DTOs). Trong mã của tôi, tôi cố gắng làm cho các DTO / Thực thể của mình tránh có các hành vi. Chúng chỉ là một API đẹp để lưu trữ trạng thái hiện tại của mô hình của tôi.

Khi bạn nói về OO và RẮN, bạn thường nói về một "đối tượng" không đại diện cho trạng thái (nhất thiết), nhưng thay vào đó đại diện cho một loại dịch vụ trả lời câu hỏi cho bạn hoặc bạn có thể ủy thác một số công việc của mình . Ví dụ:

interface IProductRepository
{
    void SaveNewProduct(IProduct product);
    IProduct GetProductById(ProductId productId);
    bool TryGetProductByName(string name, out IProduct product);
}

interface IProduct
{
    ProductId Id { get; }
    string Name { get; }
}

class ExistingProduct : IProduct
{
    public ProductId Id { get; private set; }
    public string Name { get; private set; }
}

Sau đó, thực tế của bạn ProductRepositorysẽ trả về một ExistingProductđối với GetProductByProductIdphương pháp vv

Bây giờ bạn đang tuân theo nguyên tắc trách nhiệm duy nhất (bất kỳ kế thừa nào IProductchỉ là giữ trạng thái và bất kỳ kế thừa nào từ đó IProductRepositoryđều có trách nhiệm để biết cách duy trì và bù nước cho mô hình dữ liệu của bạn).

Nếu bạn thay đổi lược đồ cơ sở dữ liệu của mình, bạn có thể thay đổi triển khai kho lưu trữ của mình mà không thay đổi DTO, v.v.

Vì vậy, trong ngắn hạn, tôi đoán tôi sẽ không chọn tùy chọn nào của bạn. :)


0

Các phương thức tĩnh có thể khó kiểm tra hơn, nhưng điều đó không có nghĩa là bạn không thể sử dụng chúng - bạn chỉ cần thiết lập chúng để bạn không cần phải kiểm tra chúng.

Tạo cả hai sản phẩm.GetReview và đánh giá. Sản phẩm một phương thức giống như

new ReviewService().GetReviews(productID);

ReviewService chứa tất cả các mã phức tạp hơn và có giao diện được thiết kế để kiểm tra, nhưng không được tiếp xúc trực tiếp với người dùng.

Nếu bạn phải có phạm vi bảo hiểm 100%, hãy kiểm tra tích hợp của bạn, gọi phương thức lớp sản phẩm / đánh giá.

Nó có thể hữu ích nếu bạn nghĩ về thiết kế API công cộng thay vì thiết kế lớp - trong bối cảnh đó, một giao diện đơn giản với nhóm hợp lý là tất cả những vấn đề - cấu trúc mã thực tế chỉ quan trọng đối với các nhà phát triển.

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.