Có ổn không khi có một lớp chỉ có thuộc tính cho mục đích tái cấu trúc?


79

Tôi có một phương thức có 30 tham số. Tôi lấy các tham số và đặt chúng vào một lớp, để tôi có thể chỉ truyền một tham số (lớp) vào phương thức. Nó có hoàn toàn tốt trong trường hợp cấu trúc lại để truyền vào một đối tượng đóng gói tất cả các tham số ngay cả khi đó là tất cả những gì nó chứa.


Các câu trả lời dưới đây là tốt. Tôi luôn thiết lập một lớp học cho mục đích này. Bạn có đang sử dụng thuộc tính Tự động không? msdn.microsoft.com/en-us/library/bb384054.aspx
Harv

Nếu không được gọi là loại POD (dữ liệu thuần túy cũ).
new123456

17
Mặc dù nhiều câu trả lời được đưa ra là tuyệt vời và thực sự là một ý kiến ​​hay nếu bạn cấu trúc lại các tham số đó thành một thứ dễ xử lý hơn một chút, tôi sẽ nói rằng thực tế là phương pháp này cần 30 phần dữ liệu khác nhau để thực hiện công việc của nó là một dấu hiệu. rằng nó đang làm quá nhiều. Nhưng một lần nữa, chúng tôi chưa thấy phương pháp được đề cập, hoặc thậm chí không biết mục đích của nó.
người dùng

1
Vì vậy, phương thức đó đã lấy tất cả các tham số, bạn có chuyển nó vào lớp mới không? Hay phương thức cũ chỉ lấy lớp mới làm tham số duy nhất của nó? Tôi sẽ xem xét việc đưa phương thức vào lớp mới, nếu nó có ý nghĩa. Các lớp chỉ có dữ liệu và không có phương thức nào được gọi là các lớp thiếu máu và có cảm giác ít OO hơn một chút. Tuy nhiên, không phải là một quy tắc khó và nhanh, chỉ là một cái gì đó để xem xét.
Kurt

@Michael: Tôi đồng ý với bạn. Một điểm khác - tôi tin rằng bạn không nên tạo đối tượng dành riêng cho phương thức trừ khi bên trong của nó có mối quan hệ bên ngoài phương thức.
Saturn Technologies

Câu trả lời:


75

Đó là một ý tưởng tuyệt vời. Ví dụ, đó là cách các hợp đồng dữ liệu được thực hiện trong WCF.

Một ưu điểm của mô hình này là nếu bạn thêm một tham số mới, người tiêu dùng của lớp không cần phải thay đổi chỉ để thêm tham số.

Như David Heffernan đã đề cập, nó có thể giúp tự ghi lại mã:

FrobRequest frobRequest = new FrobRequest
{
    FrobTarget = "Joe",
    Url = new Uri("http://example.com"),
    Count = 42,
};
FrobResult frobResult = Frob(frobRequest);

Tuyệt quá. Tôi có ấn tượng rằng chỉ cần có một lớp có thuộc tính và không có phương thức nào là vô ích.
Xaisoft 10/11/11

2
Nếu nó sẽ chỉ chứa các thành viên dữ liệu, tôi muốn làm cho nó có cấu trúc. Sử dụng struct tạo ấn tượng rằng nó chỉ là dữ liệu.
Yousf

28
sử dụng struct có các tác dụng phụ như sao chép ngữ nghĩa. Hãy chắc chắn rằng bạn đang nhận thức được rằng trước khi đưa ra quyết định như vậy
Adrian Zanescu

Đây là cách mà các mô-đun javascript thường được viết, và nó có vẻ là phương pháp tốt nhất để chấp nhận nhiều hơn hoặc ít hơn các tham số khi mô-đun trưởng thành. someFunction ({myParam1: 'something', myParam2: 'somethingElse'});
Kristian

63

Trong khi các câu trả lời khác ở đây chỉ ra một cách chính xác rằng việc truyền một thể hiện của một lớp tốt hơn việc truyền 30 tham số, hãy lưu ý rằng một số lượng lớn các tham số có thể là dấu hiệu của một vấn đề cơ bản.

Ví dụ: nhiều khi các phương thức tĩnh tăng lên về số lượng tham số của chúng, bởi vì chúng lẽ ra phải là các phương thức cá thể và bạn đang truyền rất nhiều thông tin có thể dễ dàng được duy trì hơn trong một phiên bản của lớp đó.

Ngoài ra, hãy tìm cách nhóm các tham số thành các đối tượng có mức trừu tượng cao hơn. Đưa một loạt các tham số không liên quan vào một lớp là biện pháp cuối cùng IMO.

Xem Có bao nhiêu tham số là quá nhiều? để biết thêm một số ý tưởng về điều này.


Theo nghĩa nào thì các tham số này không liên quan? Chúng đều được sử dụng theo phương pháp này. Đó là một mối quan hệ rất bền chặt. Hơn nữa, các tham số trên ngăn xếp thường thích hợp hơn với trạng thái. Suy nghĩ về đa luồng.
David Heffernan vào

12
Điều đó không thể được trả lời nếu không nhìn thấy mã OP, nhưng tôi không đồng ý rằng đơn giản vì hai giá trị được sử dụng cùng nhau trong một phương thức, chúng có mối quan hệ chặt chẽ. Nếu điều đó là đúng, thiết kế OO sẽ có nghĩa là tạo ra một lớp lớn chứa mọi thuộc tính có thể được sử dụng trong ứng dụng của bạn.
D'Arcy Rittich 10/11/11

Không bạn đúng, không nhất thiết phải liên quan. Nhưng cũng không hẳn là không liên quan. Vì vậy, như bạn nói, sẽ cần phải xem mã để chắc chắn.
David Heffernan,

23
30 tham số? Tôi muốn giải quyết hầu hết các phương pháp có lẽ không liên quan và cũng có thể là dấu hiệu của một phương pháp quá dài, có độ phức tạp chu kỳ cao và là nơi ẩn náu của các lỗi. Hãy cân nhắc rằng chúng ta đang nói về một phương pháp mà hành vi của nó có ít nhất 30 thứ nguyên mà nó có thể khác nhau. Nếu có các bài kiểm tra đơn vị cho phương pháp này, tôi sẽ không muốn là người viết chúng TBH.
Steve Rowbotham 10/11/11

3
Một tình huống có thể xảy ra khác là tất cả các tham số đều có liên quan nhưng chúng được tổ chức kém. Rất có thể các nhóm tham số nên được gộp thành các đối tượng riêng biệt hơn là được chuyển xung quanh từng phần. Giả sử tôi có một phương thức hoạt động dựa trên thông tin như "người", "địa chỉ", "đơn thuốc" ... có thể dễ dàng lên tới 30 tham số nếu từng phần thông tin rời rạc được chuyển vào phương thức của tôi riêng biệt.
CK Nate

25

Đó là một khởi đầu tốt. Nhưng bây giờ bạn đã có lớp mới đó, hãy xem xét chuyển mã của bạn từ trong ra ngoài. Di chuyển phương thức nhận lớp đó làm tham số vào lớp mới của bạn (tất nhiên, truyền một thể hiện của lớp ban đầu làm tham số). Bây giờ bạn đã có một phương thức lớn, một mình trong một lớp và sẽ dễ dàng tách nó thành các phương thức nhỏ hơn, dễ quản lý hơn, có thể kiểm tra được. Một số phương thức đó có thể chuyển trở lại lớp ban đầu, nhưng một phần nhỏ có thể sẽ nằm trong lớp mới của bạn. Bạn đã vượt ra ngoài Giới thiệu Đối tượng Tham số để Thay thế Phương thức bằng Đối tượng Phương thức .

Có một phương thức với ba mươi tham số là một dấu hiệu khá mạnh cho thấy phương thức này quá dài và quá phức tạp. Quá khó để gỡ lỗi, quá khó để kiểm tra. Vì vậy, bạn nên làm gì đó với nó, và Giới thiệu Đối tượng Tham số là một nơi tốt để bắt đầu.


4
Điều này TUYỆT ĐỐI QUAN TRỌNG! Việc tạo các gói thuộc tính này chỉ là điều tuyệt vời vì đó là bước đầu tiên để tạo các lớp mới với các phương thức của riêng chúng và bạn sẽ luôn tìm thấy các phương thức thuộc về các lớp mới của mình - hãy tìm chúng! Tôi nghĩ đây là câu trả lời quan trọng nhất trong nhóm này, nó phải ở gần đầu.
Bill K

15

Trong khi việc tái cấu trúc lại đối tượng Tham số không phải là một ý tưởng tồi, nó không nên được sử dụng để che giấu vấn đề rằng một lớp cần 30 phần dữ liệu được cung cấp từ nơi khác vẫn có thể là một thứ gì đó có mùi mã. Việc tái cấu trúc Đối tượng Tham số Giới thiệu có lẽ nên được coi là một bước trong quá trình tái cấu trúc rộng hơn chứ không phải là phần cuối của quy trình đó.

Một trong những mối quan tâm mà nó không thực sự giải quyết là tính năng Envy. Việc lớp được truyền Đối tượng tham số rất quan tâm đến dữ liệu của lớp khác không chỉ ra rằng có thể các phương thức hoạt động trên dữ liệu đó nên được chuyển đến nơi dữ liệu cư trú? Thực sự tốt hơn nếu xác định các cụm phương thức và dữ liệu thuộc về nhau và nhóm chúng thành các lớp, do đó tăng khả năng đóng gói và làm cho mã của bạn linh hoạt hơn.

Sau nhiều lần lặp lại việc tách hành vi và dữ liệu mà nó hoạt động thành các đơn vị riêng biệt, bạn sẽ thấy rằng bạn không còn có bất kỳ lớp nào với số lượng lớn các phụ thuộc luôn là kết quả cuối cùng tốt hơn vì nó sẽ làm cho mã của bạn linh hoạt hơn.


10

Đó là một ý tưởng tuyệt vời và là một giải pháp rất phổ biến cho vấn đề. Các phương thức có nhiều hơn 2 hoặc 3 tham số trở nên khó hơn và khó hiểu hơn theo cấp số nhân.

Việc đóng gói tất cả điều này trong một lớp duy nhất giúp mã rõ ràng hơn nhiều. Vì thuộc tính của bạn có tên nên bạn có thể viết mã tự ghi lại như sau:

params.height = 42;
params.width = 666;
obj.doSomething(params);

Đương nhiên, khi bạn có nhiều tham số, việc thay thế dựa trên nhận dạng vị trí chỉ đơn giản là kinh khủng.

Tuy nhiên, một lợi ích khác là việc thêm các tham số bổ sung vào hợp đồng giao diện có thể được thực hiện mà không buộc phải thay đổi ở tất cả các trang web cuộc gọi. Tuy nhiên, điều này không phải lúc nào cũng tầm thường như người ta tưởng. Nếu các trang web cuộc gọi khác nhau yêu cầu các giá trị khác nhau cho thông số mới, thì việc tìm kiếm chúng sẽ khó hơn so với phương pháp dựa trên thông số. Trong cách tiếp cận dựa trên tham số, việc thêm một tham số mới buộc phải thay đổi tại mỗi trang web cuộc gọi để cung cấp tham số mới và bạn có thể để trình biên dịch thực hiện công việc tìm kiếm tất cả chúng.



5

30 tham số là một mớ hỗn độn. Tôi nghĩ rằng sẽ đẹp hơn khi có một lớp với các thuộc tính. Bạn thậm chí có thể tạo nhiều "lớp tham số" cho các nhóm tham số phù hợp trong cùng một danh mục.


3

Bạn cũng có thể xem xét sử dụng một cấu trúc thay vì một lớp.

Nhưng những gì bạn đang cố gắng làm rất phổ biến và là một ý tưởng tuyệt vời!


Tôi thực sự đã nghĩ về việc sử dụng một cấu trúc, nhưng tôi tò mò liệu có bất kỳ điều gì bất lợi nếu tôi sử dụng một cấu trúc hay không.
Xaisoft 10/11/11

Tại sao David? Số trường có liên quan gì đến nó? Chỉ tò mò.
Tad Donaghe

2
Như một vấn đề hiệu suất. Mặc dù về mặt ngữ nghĩa, sẽ hợp lý hơn khi sử dụng một cấu trúc ở đây vì chỉ giá trị của mỗi trường là quan trọng và danh tính tham chiếu là không liên quan, hơn 30 trường cần sao chép (giả sử chúng chủ yếu là các loại tham chiếu; 120byte trên 32 bit và 240byte trên 64) so ​​với một lớp (4 hoặc 8 byte). Tuy nhiên, bản chất sao chép theo giá trị của cấu trúc có nghĩa là khi được sao chép qua quyền truy cập sẽ nhanh hơn so với kiểu tham chiếu, do đó, ngưỡng mà cấu trúc kém hiệu quả hơn sẽ cao hơn kích thước 1 con trỏ ở trên. Tại> 4 kích thước con trỏ-thời gian để xem xét nó.
Jon Hanna

Tuyệt vời. Cảm ơn vì lời giải thích! :)
Tad Donaghe

3

Có thể hợp lý khi sử dụng lớp Dữ liệu cũ thuần túy cho dù bạn đang cấu trúc lại hay không. Tôi tò mò là tại sao bạn nghĩ rằng nó có thể không.


Tôi không nhớ chính xác, nhưng tôi nghĩ rằng khi tôi đề cập ở đâu đó trên đây rằng tôi đang tạo một lớp chỉ với các thuộc tính, nó đã bị coi thường vào thời điểm đó. Về điểm thứ hai, bạn đang nói rằng chỉ các tham số không thay đổi mới được truyền vào phương thức, nói cách khác, nếu phương thức thay đổi tham số, thì nó không nên được truyền dưới dạng tham số.
Xaisoft 10/11/11

Các lớp chỉ là thuộc tính có thể có mùi hôi (xem câu trả lời của Steve Rowbotham) cho biết một thứ gì đó nên là một lớp "đầy đủ". Một dấu hiệu tốt là nếu bạn kết thúc sử dụng các lớp tương tự nhiều hơn một lần. Tuy nhiên, điều này không phải lúc nào cũng đúng như vậy, và trong một sự thay đổi giữa một lớp 30 trường và một phương thức 30 tham số, có một lời gọi tốt để dựa vào cái trước. Bên cạnh đó, nó có thể là một sự khởi đầu cho việc xây dựng lớp học "đầy đủ" đó.
Jon Hanna

... Tôi đang xóa nhận xét của mình về tính bất biến, vì tôi đã nghĩ nhiều hơn về lớp này chỉ là một phương thức công khai (trong đó một đối tượng "yêu cầu" mô tả ý định của người gọi). Ở đây thay đổi "yêu cầu" có thể dẫn đến nhầm lẫn. Trong trường hợp một lần, bạn có thể thay đổi và xây dựng theo cách của bạn. Tính bất biến chỉ có nghĩa là thay thế một lệnh gọi 30 đối số bằng một hàm tạo 30 đối số theo sau là một lệnh gọi, vì vậy sẽ không có chiến thắng.
Jon Hanna

3

Có lẽ các tham số tùy chọn và được đặt tên của C # 4.0 là một sự thay thế tốt cho điều này?

Dù sao, phương thức bạn đang mô tả cũng có thể tốt cho việc trừu tượng hóa hành vi của chương trình. Ví dụ, bạn có thể có một SaveImage(ImageSaveParameters saveParams)chức năng tiêu chuẩn trong Giao diện trong đó ImageSaveParameterscũng là một giao diện và có thể có các tham số bổ sung tùy thuộc vào định dạng hình ảnh. Ví dụ JpegSaveParametersQuality-property trong khi PngSaveParametersBitDepth-property.

Đây là cách hộp thoại lưu save trong Paint.NET thực hiện vì vậy nó là một ví dụ rất thực tế.


3

Như đã nêu trước đây: đó là bước đúng đắn cần làm, nhưng cũng hãy xem xét những điều sau:

  • phương thức của bạn có thể quá phức tạp (bạn nên cân nhắc việc chia nó thành nhiều phương thức hơn hoặc thậm chí biến nó thành một lớp riêng biệt)
  • nếu bạn tạo lớp cho các tham số, hãy làm cho nó bất biến
  • nếu nhiều tham số có thể là rỗng hoặc có thể có một số giá trị mặc định, bạn có thể muốn sử dụng mẫu trình tạo cho lớp của mình.

0

Rất nhiều câu trả lời tuyệt vời ở đây. Tôi muốn thêm hai xu của tôi.

Đối tượng tham số là một khởi đầu tốt. Nhưng còn nhiều điều có thể làm được. Hãy xem xét những điều sau (ví dụ về ruby):

/ 1 / Thay vì chỉ nhóm tất cả các tham số, hãy xem liệu có thể nhóm các tham số có ý nghĩa hay không. Bạn có thể cần nhiều hơn một đối tượng tham số.

def display_line(startPoint, endPoint, option1, option2)

có thể trở thành

def display_line(line, display_options)

/ 2 / Đối tượng tham số có thể có số lượng thuộc tính ít hơn số lượng tham số ban đầu.

def double_click?(cursor_location1, control1, cursor_location2, control2)

có thể trở thành

def double_click?(first_click_info, second_click_info) 
                       # MouseClickInfo being the parameter object type 
                       # having cursor_location and control_at_click as properties

Việc sử dụng như vậy sẽ giúp bạn khám phá các khả năng thêm hành vi có ý nghĩa vào các đối tượng tham số này. Bạn sẽ thấy rằng chúng loại bỏ mùi Lớp dữ liệu ban đầu của chúng sớm hơn để bạn thoải mái hơ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.