Đây có phải là mùi mã nếu một đối tượng biết nhiều chủ sở hữu của nó?


9

Trong ứng dụng Delphi 2007 của chúng tôi, chúng tôi đang sử dụng rất nhiều cấu trúc sau

FdmBasic:=TdmBasicData(FindOwnerClass(AOwner,TdmBasicData));

FindOwnerClass di chuyển phân cấp Chủ sở hữu của thành phần hiện tại lên trên để tìm một lớp cụ thể (trong ví dụ TdmBasicData). Đối tượng kết quả được lưu trữ trong biến Trường FdmBasic. Chúng tôi sử dụng điều này chủ yếu để vượt qua các datamodules cùng.

Ví dụ: Khi tạo báo cáo, dữ liệu kết quả được nén và lưu trữ trong trường Blob của bảng được truy cập thông qua biểu dữ liệu TdmReportBaseData. Trong một mô-đun riêng của ứng dụng của chúng tôi, có chức năng hiển thị dữ liệu từ báo cáo ở dạng Paged bằng cách sử dụng ReportBuilder. Mã chính của mô-đun này (TdmRBReport), sử dụng lớp TRBTempdatabase để chuyển đổi dữ liệu blob nén thành các bảng khác nhau có thể sử dụng được trong trình báo cáo thời gian chạy của Trình xây dựng báo cáo. TdmRBReport có quyền truy cập vào TdmReportBaseData cho tất cả các loại dữ liệu liên quan đến báo cáo (loại báo cáo, cài đặt tính toán báo cáo, v.v.). TRBTempDatabase được xây dựng trong TdmRBReport nhưng phải có quyền truy cập vào TdmReportBasingata. Vì vậy, điều này bây giờ được thực hiện bằng cách sử dụng xây dựng ở trên:

constructor TRBTempDatabase.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(FindOwnerClass(Owner, TdmRBReport)).dmReportBaseData;
end;{- .Create }

Cảm giác của tôi là điều này có nghĩa là TRBTempDatabase biết rất nhiều chủ sở hữu của nó và tôi đã tự hỏi liệu đây có phải là một loại mùi mã hay Anti-pattern.

suy nghĩ của bạn về điều này là gì? Đây có phải là một mùi mã? Nếu vậy, một cách tốt hơn là gì?


1
Nếu nó được cho là biết nhiều về một lớp khác thì nó sẽ được cung cấp một cách dễ dàng hơn để làm điều đó.
Loren Pechtel

Câu trả lời:


13

Kiểu này trông giống như Mẫu Định vị Dịch vụ được mô tả lần đầu tiên bởi Martin Fowler (đã được xác định là mẫu chống phổ biến).

Tiêm phụ thuộc dựa trên xây dựng được ưa thích hơn Bộ định vị dịch vụ vì nó thúc đẩy khả năng hiển thị các tham số yêu cầu và thúc đẩy Kiểm tra đơn vị đơn giản hơn.

Vấn đề với việc sử dụng Trình định vị dịch vụ không phải là bạn phụ thuộc vào việc triển khai Trình định vị dịch vụ cụ thể (mặc dù đó cũng có thể là một vấn đề), nhưng đó là một mô hình chống đối. Nó sẽ mang đến cho người tiêu dùng API của bạn trải nghiệm khủng khiếp dành cho nhà phát triển và điều đó sẽ khiến cuộc sống của bạn với tư cách là nhà phát triển bảo trì trở nên tồi tệ hơn vì bạn sẽ cần sử dụng lượng năng lượng não đáng kể để nắm bắt ý nghĩa của mọi thay đổi bạn thực hiện.

Trình biên dịch có thể cung cấp cho cả người tiêu dùng và nhà sản xuất rất nhiều trợ giúp khi Con Contortor được sử dụng, nhưng không có trợ giúp nào có sẵn cho các API dựa trên Trình định vị dịch vụ.

Ngoài ra, đáng chú ý nhất là nó cũng vi phạm Luật Demeter

Luật Demeter (LoD) hoặc Nguyên tắc tối thiểu của kiến ​​thức là một hướng dẫn thiết kế để phát triển phần mềm, đặc biệt là các chương trình hướng đối tượng. Ở dạng chung, LoD là một trường hợp cụ thể của khớp nối lỏng lẻo.

Định luật Demeter cho các hàm yêu cầu một phương thức M của một đối tượng O chỉ có thể gọi các phương thức của các loại đối tượng sau:

  1. Ôi chính nó
  2. Thông số của M
  3. bất kỳ đối tượng nào được tạo / khởi tạo trong M
  4. Đối tượng thành phần trực tiếp của O
  5. một biến toàn cục, có thể truy cập bằng O, trong phạm vi của M

Cụ thể, một đối tượng nên tránh gọi các phương thức của một đối tượng thành viên được trả về bởi một phương thức khác. Đối với nhiều ngôn ngữ hướng đối tượng hiện đại sử dụng dấu chấm làm định danh trường, luật có thể được chỉ định đơn giản là "chỉ sử dụng một dấu chấm". Đó là, mã abMethod () vi phạm luật mà a.Method () không có. Một ví dụ đơn giản, khi một người muốn dắt chó đi dạo, sẽ thật điên rồ khi ra lệnh cho chân của chó đi thẳng; thay vào đó, người ta ra lệnh cho con chó và để nó tự chăm sóc đôi chân của mình.

Cách tốt hơn

Thực tế, cách tốt hơn là loại bỏ cuộc gọi định vị dịch vụ trong lớp và chuyển vào đúng chủ sở hữu như một tham số bên trong hàm tạo của nó. Ngay cả khi điều này có nghĩa là bạn có một lớp dịch vụ thực hiện tra cứu chủ sở hữu và sau đó chuyển nó đến hàm tạo của lớp

constructor TRBTempDatabase.Create(aOwner: TComponent, ownerClass: IComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(ownerClass).dmReportBaseData;
end;{- .Create }

3
Câu trả lời tuyệt vời và đạo cụ cho bất cứ ai nghĩ ra sự tương tự tuyệt vời này:As a simple example, when one wants to walk a dog, it would be folly to command the dog's legs to walk directly; instead one commands the dog and lets it take care of its own legs.
Andy Hunt

3

Một trong những khó khăn khi có các đối tượng trẻ biết quá nhiều về cha mẹ là bạn kết thúc việc thực hiện các mô hình có thể (và thường xuyên nhất) trở nên quá chặt chẽ, điều này tạo ra những cơn đau đầu phụ thuộc lớn và sau đó trở nên rất khó để sửa đổi và duy trì an toàn sau này

Tùy thuộc vào mức độ hai lớp của bạn được kết nối sâu sắc như thế nào, nghe có vẻ giống như mô tả của Fowler về tính năng ghen tị của tính năng hoặc sự thân mật không phù hợp có thể thấy rõ.

Dường như cần phải tải hoặc đọc một lớp có dữ liệu, trong trường hợp đó bạn có thể sử dụng một số mẫu thay thế để phá vỡ sự phụ thuộc giữa trẻ và chuỗi của cha mẹ và có vẻ như bạn cần ủy thác nhiệm vụ truy cập lớp dữ liệu của bạn thay vì làm cho lớp truy cập dữ liệu chịu trách nhiệm tự làm mọi thứ.

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.