Khi nào tôi nên sử dụng lớp 2 thuộc tính trên cấu trúc dựng sẵn như KeyValuePair?


31

Khi nào bạn nên đặt loại dữ liệu Khóa / Giá trị trong lớp của chính nó thay vì sử dụng cấu trúc chung được xây dựng trước, chẳng hạn như a KeyValuePairhoặc a Tuple?

Ví dụ: hầu hết các ComboBox tôi tạo đều chứa DisplayName và Value. Đây là loại dữ liệu tôi đang cố gắng quyết định khi nào nên đưa vào một lớp mới và khi nào chỉ nên sử dụng KeyValuePair.

Tôi hiện đang làm việc trên một cái gì đó sử dụng iCalendarvà dữ liệu của người dùng được chọn cuối cùng được kết hợp thành một key1=value1;key2=value2;loại chuỗi. Tôi đã bắt đầu bằng cách đưa dữ liệu vào một KeyValuePair<string,string>, nhưng bây giờ tôi tự hỏi liệu đó có phải là lớp riêng không.

Nhìn chung, tôi quan tâm đến việc tìm hiểu những hướng dẫn nào được sử dụng khi quyết định sử dụng cấu trúc / lớp hiện có như KeyValuePairđối tượng trên 2 thuộc tính và trong trường hợp nào bạn sẽ sử dụng loại tình huống này.


3
Ngôn ngữ nào? Trong Python, chúng tôi không gặp vấn đề nan giải này, vì chúng tôi có tupleloại.
S.Lott

3
@ S.Lott - .NET BCL có bộ dữ liệu kể từ phiên bản 4.0.
Oded


1
@Oded Trong trường hợp này, tôi đang xây dựng một cái gì đó với iCalendarvà tôi muốn các đối tượng cho BYDAYBYSETPOS. Chúng xuất hiện trong ComboBox, nhưng dữ liệu thực tế được kết hợp thành chuỗi quy tắc định kỳ, đó là một key=value;loại chuỗi
Rachel

4
@Rachel: Vui lòng cập nhật câu hỏi để cụ thể hơn. Một loạt các ý kiến ​​không phải là cách tốt nhất để làm rõ mọi thứ.
S.Lott

Câu trả lời:


26

Tôi thường sử dụng một đối tượng chứ không phải là KeyValuePair hoặc Tuple trong hầu hết các trường hợp. Đầu tiên, khi bạn đến sau 6 tháng để thực hiện thay đổi, sẽ dễ dàng hơn rất nhiều để tìm ra ý định của bạn trước đó thay vì tự hỏi điều gìTuple t là và tại sao nó có những giá trị hài hước đó. Thứ hai, khi mọi thứ phát triển và thay đổi, bạn có thể dễ dàng đưa ra hành vi đối tượng truyền dữ liệu đơn giản của mình theo yêu cầu. Cần phải có hai định dạng tên? Dễ dàng, chỉ cần thêm quá tải ToString () thích hợp. Cần nó để thực hiện một số giao diện? Không vấn đề gì. Cuối cùng, thực sự có gần như không có chi phí để tạo một đối tượng đơn giản, đặc biệt là với các thuộc tính tự động và hoàn thành mã.

Bonus Protip: nếu bạn muốn giữ cho các đối tượng này không làm ô nhiễm không gian tên của bạn, tạo các lớp riêng bên trong các lớp là một cách tuyệt vời để giữ mọi thứ trong bọc và ngăn chặn các phụ thuộc lạ.


1
DTOs = Đối tượng truyền dữ liệu ? - Tôi ghét TLAs ;-)
Ben

3
@Ben - MẠNH M .. . .
Wyatt Barnett

7

Quy tắc để xác định một lớp mới rất đơn giản: Nó được tóm tắt bởi "Occam's Razor".

http://c2.com/cgi/wiki?OccamsRazor

Đừng giới thiệu các lớp học mới mà không có lý do chính đáng. Hoặc sử dụng các lớp dựng sẵn càng nhiều càng tốt. Hoặc phát minh càng ít càng tốt. Tuy nhiên, bạn cảm thấy thoải mái khi viết ít mã hơn.

Bạn không thể sử dụng một lớp dựng sẵn nếu bạn phải gán một số trách nhiệm duy nhất cho đối tượng và trách nhiệm đó không được xác định trong lớp dựng sẵn. Thường thì đây là một phương pháp độc đáo.

A tuplehoặc KeyValuePairđược ưa thích.

Cho đến khi.

Bạn cần một số chức năng không phải là một phần của A tuplehoặc KeyValuePair. Sau đó, bạn phải xác định lớp học của riêng bạn.


3
" Không bao giờ thiết kế những gì bạn có thể ăn cắp " là về cách yêu thích của tôi về cụm từ này.
SingleNegationElimination

1
Bạn có coi ngữ nghĩa là "chức năng không phải là một phần của " tuplehay KeyValuePairkhông? KeyValuePair ít nhất có một số dạng ngữ nghĩa hạn chế, nhưng tuples hiếm khi làm (có thể là có thể, tùy thuộc vào ngữ cảnh) imho. Giới thiệu một lớp học mới sẽ cung cấp cho bạn ngữ nghĩa rõ ràng là một vấn đề tất nhiên.
Mal Ross

+1 Đừng vá toàn bộ trong thuyền bằng băng keo nếu nó có thể vừa với phích cắm.
Evan Plaice

4
Tôi nghĩ rằng đây là việc sử dụng sai dao cạo của Occam. Thứ hai, điều quan trọng là phải biết thông tin nào được chứa trong một biến. -1.
Bent

4

Nếu bạn viết lớp của riêng bạn, bạn có một nơi rõ ràng để đặt tài liệu về hai giá trị là gì. Đặc biệt là vì hai chuỗi không phải là một định nghĩa rất rõ ràng. Tuy nhiên bạn có thể viết một cái gì đó như

 public class MyPair : Tuple<string, string>

Tôi thích điều này bởi vì MyPairđịnh nghĩa các giá trị Tuple là gì và chúng được sử dụng để làm gì.
I Ab.

2
Nhưng sau đó tài sản của bạn sẽ được gọi Item1Item2! Không phải là dễ dàng để xác định toàn bộ lớp sao? public class SideStrings { public string Left { get; set; } public string Right { get; set; } }
cấu hình

@configurator Tôi đã viết một phản hồi cho điều đó và nhận thấy rằng Tuple chỉ được đọc nên tôi đồng ý rằng tôi nghĩ rằng nó đã bắn ra toàn bộ. Mặc dù bạn có thể bọc bộ dữ liệu để đặt tên cho các giá trị bất cứ điều gì bạn muốn.

2
@Sign: Nhưng quan điểm là gì? Tạo lớp của riêng bạn là công việc ít hơn so với gói một tuple.
cấu hình

2
@configurator bạn nhận được một số công cụ bình đẳng và so sánh hoạt động tốt hơn một đối tượng tùy chỉnh, nhưng nếu cài đặt được yêu cầu, bộ dữ liệu chắc chắn là cách sai.

4

S.Lott đã viết

Đừng giới thiệu các lớp học mới mà không có lý do chính đáng. Hoặc sử dụng các lớp dựng sẵn càng nhiều càng tốt. Phát minh càng ít càng tốt.

Bạn không thể sử dụng một lớp dựng sẵn nếu bạn phải gán một số trách nhiệm duy nhất cho đối tượng không được xác định trong lớp dựng sẵn.

Hãy để tôi nói tại sao tôi có một vấn đề nghiêm trọng với điều này. Kể từ khi

KeyValuePair [chuỗi, chuỗi]

có vẻ ổn .... liệu KeyValue [chuỗi, KeyValue [chuỗi, KeyValuePair [chuỗi, chuỗi]]] cũng ổn chứ? Tôi không biết những gì S. Lott sẽ nói điều này, nhưng ông chủ của tôi nghĩ rằng nó ổn.

Tôi dám không đồng ý. Và đây là lý do: Nó làm giảm tính dễ đọc của mã sẽ tuân theo. Hàm sẽ điền vào cấu trúc dữ liệu như vậy sẽ phức tạp hơn và dễ bị lỗi (err .. ngoại lệ) (chỉ cần tưởng tượng ít nhất là một số logic kinh doanh là tốt). Tôi đã không tranh luận với sếp quá nhiều, nhưng tôi sẽ nói ở đây: Khả năng đọc vượt qua tiết kiệm không gian phút (đó là lý lẽ của anh ấy ). Vì vậy, sẽ không một đối tượng lớp trong đó có một số lĩnh vực; nhưng một số vẫn còn trống tại một số thời điểm tốt hơn?

PS Tôi là một Ultra_Noob vì vậy xin vui lòng cho tôi biết nếu tôi sai.


2
Tôi nghĩ điều đó KeyValuePair<string,string>là tốt, giả sử những thứ được đưa vào thực sự là chìa khóa và giá trị. Ở đây, sử dụng lại một lớp hiện có là một chiến thắng, vì bạn lưu mã viết và đạt được khả năng tương tác. OTOH, sử dụng một cái gì đó phức tạp như KeyValuePair<string,KeyValuePair<string,string>>hầu hết thời gian đơn giản là quá phức tạp để trở nên thiết thực. Đôi khi nó có thể đúng - khi bạn không cần chức năng bổ sung, khi ý nghĩa rõ ràng và khi nó hoạt động độc đáo với các lớp khác. YMMV, đây chỉ là trọng số của ưu và nhược điểm.
maaartinus

Nếu bạn đang sử dụng C #, đây là hiệu suất của Tuple vs KeyValuePair . Một cái gì đó bạn có thể muốn chia sẻ với sếp của bạn?
Ben

3

Khi chúng ta nói cặp khóa / giá trị , tôi thường nghĩ về các bảng băm hoặc mảng kết hợp hoặc đơn giản là một đối tượng KeyValuePair . Tôi sử dụng tất cả chúng và không có sự khác biệt khi tôi sử dụng.

Tôi nghĩ điều quan trọng nhất về danh sách các cặp khóa / giá trị là, các khóa phải là duy nhất (vì tất cả là khóa) và tất cả các cấu trúc đã nói ở trên thực sự cung cấp cho tôi chức năng đó.

Ngoài ra, tôi muốn tìm kiếm theo các phím hoặc thực hiện các hành động kiểu danh sách (mảng) như đẩy và bật.

Vì vậy, câu trả lời của tôi là KHÔNG , và tôi không tạo các đối tượng rõ ràng cho các cặp khóa / giá trị, vì rất nhiều cấu trúc dựng sẵn đã làm điều đó cho tôi.


3

Chương sáu của Clean Code có một mô tả hay về thời điểm sử dụng cấu trúc dữ liệu so với một lớp. Tóm lại, bạn sử dụng cấu trúc dữ liệu khi bạn chủ yếu dự đoán thêm các chức năng mới để vận hành trên dữ liệu đó. Bạn sử dụng một lớp khi bạn chủ yếu dự đoán thêm các loại dữ liệu mới sẽ được vận hành bởi các chức năng hiện có. ComboBox của bạn là một ví dụ về cái sau. Bạn có một bộ chức năng (triển khai ComboBox) hoạt động trên nhiều loại dữ liệu khác nhau (các loại dữ liệu khác nhau cho các tiện ích khác nhau).


2

Tôi có lẽ sẽ đồng ý với Wishing ở đây , nhưng sau đó tôi cũng có một chút gì đó về loại điều này.

Tôi muốn đề xuất rằng các loại tích hợp thường là các đối tượng cơ chế . Ví dụ, KeyValuePair là một phần của cơ chế của bảng từ điển và bảng băm, giúp đảm bảo các khóa duy nhất và chúng có các thuộc tính có tên có ý nghĩa trong bối cảnh của chính cơ chế.

Mặt khác, sử dụng các đối tượng dữ liệu được thực hiện tùy chỉnh cung cấp sự thể hiện tốt hơn cho dữ liệu của bạn và cung cấp nhiều lợi ích, bao gồm khả năng đọc và mở rộng. Không có gì để ngừng sử dụng lại mã hiện có trong các đối tượng được xây dựng tùy chỉnh như Dấu hiệu được đề xuất , nhưng tôi sẽ thử và ẩn lớp được bọc và tránh rò rỉ trừu tượng , để bạn có thể thay đổi triển khai cơ bản tại một điểm sau mà không ảnh hưởng đến phần còn lại của mã .

Vì vậy, câu hỏi thực sự: Bạn đang đại diện cho dữ liệu hay bạn đang sử dụng dữ liệu trong một cơ chế? (và tôi sẽ không khuyên trộn các khái niệm này với nhau).

Theo kinh nghiệm của tôi, không có gì tệ hơn khi thấy một Tuple [chuỗi, chuỗi] được truyền vào một phương thức và không có cách nào ngay lập tức để biết Item1 và Item2 là gì. Tốt nhất chỉ sử dụng Tuples trong các phương thức hoặc là thành viên riêng của một lớp.

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.