Có gì khác biệt giữa các tiền tố đến giữa các loại khác nhau [đóng cửa]


78

Sự khác biệt giữa các tiền tố tên phương thức "đến""như" như thế nào

  • liệt kê(),
  • asList (),
  • Vân vân...

Khi nào nên sử dụng khi thiết kế một phương pháp?

Câu trả lời:


120

Một toXYZ()hàm được dự kiến ​​sẽ thực hiện chuyển đổi và trả về một đối tượng độc lập mới (mặc dù tính bất biến cho phép tối ưu hóa, java.lang.String.toString()chỉ trả về đối tượng).
Ví dụ, trong C ++, chúng ta có std::bitset::to_ulong()thể dễ dàng thất bại và toàn bộ rất nhiều to_string(), tất cả đều thực hiện chuyển đổi và phân bổ bộ nhớ phức tạp (ít nhiều).

asXYZ()Mặt khác, một chức năng dự kiến ​​sẽ trả về một khung nhìn (có khả năng khác nhau) của nguồn, thực hiện công việc tối thiểu.
Ví dụ, trong C ++, chúng ta có std::as_const()trả về một tham chiếu không đổi và càng tham gia nhiều hơn std::forward_as_tuplemà còn tham chiếu đến các đối số của nó bằng tham chiếu.


19
Nó chỉ ra rằng có một số tiền lệ hiện có cho việc này. Nói chung, As [một cái gì đó] sẽ giống với một diễn viên, trong khi To [một cái gì đó] xây dựng một đối tượng mới (thuộc loại khác) từ một đối tượng hiện có. Trong trường hợp của ToList, nó sẽ là O (n) và gần như chắc chắn đắt hơn một chữ "As". Xem stackoverflow.com/questions/17968469/ Mạnh
Robert Harvey

5
Đó là một phần của việc chọn tên mô tả và ngay cả khi sự khác biệt cụ thể này không được mã hóa trong tiêu chuẩn mã hóa, vi phạm nó sẽ phá vỡ Nguyên tắc ít gây ngạc nhiên nhất .
Ded repeatator

11
Tôi sẽ mô tả nó như là, theo bản năng, tôi sẽ nghĩ "thành" là "thay đổi thành" và "là" như "đối xử như". Cái trước ngụ ý làm việc để thay đổi điều, cái sau ngụ ý nó chỉ là một sự khác biệt trong cách bạn làm việc với nó.
Latty

6
Nếu nó có nghĩa là một cái gì đó, nó nên có nghĩa này. Tôi đề nghị rằng nó thường không có nghĩa gì cả, vì vậy tôi sẽ không dựa vào mã bên thứ ba ngẫu nhiên (mà không thấy điều gì trong tài liệu). Nó sẽ là một quy ước tốt để áp dụng trong một cơ sở mã mặc dù.
Ben

4
Câu trả lời này cũng chính xác trong C ++: ví dụ: std::to_string(x)tạo một đối tượng chuỗi mới, nhưng std::as_const(x)tạo một tham chiếu (một khung nhìn) của đối tượng hiện có.
Quuxplusone

13

Thành thật mà nói, nó có thể chỉ là đặt tên không nhất quán. Nếu nhìn vào đối tượng thư viện chuẩn trong Smalltalk, ví dụ, tất cả các phương pháp mà làm "chuyển đổi phức tạp" hay "trở lại cơ quan đại diện đơn giản trong kiểu khác" được bắt đầu với as, như trong asString, asFloat, asSeconds, và các phương pháp tiêu chuẩn để chuyển đổi bất cứ điều gì để bất cứ điều gì khác, as: aClass.

Trong Ruby, cùng loại của phương pháp được bắt đầu với to_, như trong to_s, to_a, to_h, viết tắt của string, arrayhashtương ứng.

Cả hai thư viện tiêu chuẩn dường như không phân biệt giữa các loại chuyển đổi khác nhau, có lẽ vì nó nên được coi là một chi tiết triển khai.

Tuy nhiên, trong Java chúng ta thấy rất nhiều sự pha trộn. Như bạn nói, có toString, asListvà vân vân. Tôi tin rằng đây chỉ là một sự không nhất quán trong cách đặt tên, bởi vì nếu bạn cố gắng xác định một ý nghĩa khác nhau cho mỗi tiền tố, bạn sẽ luôn tìm thấy một ví dụ ngược lại ở một nơi khác trong thư viện chuẩn.

Vì vậy, trong mọi trường hợp, tôi muốn nói rằng điều quan trọng là bạn và nhóm của bạn chọn một tiền tố và sử dụng nó một cách nhất quán trong toàn bộ mã. Tính nhất quán là chìa khóa, vì vậy mọi người không được tự hỏi, giống như bạn phải làm.


1
Tôi không tin vào: chọn một kiểu cho cả nhóm, thay vì chọn một kiểu cho các trường hợp tương tự trong một mô-đun, một cách nhất quán.
Daniel Hári

12
Trong Java, toStringtạo một chuỗi mới bị ngắt kết nối hoàn toàn khỏi đối tượng (và không có cách nào khác vì tính bất biến). Các ví dụ tương tự, ví dụ, Collection#toArraytrong khi Arrays#asListtrả về một khung nhìn của mảng, được kết nối hai chiều (việc thay đổi mảng sẽ thay đổi danh sách và ngược lại). Vì vậy, nó khá nhất quán, mặc dù có thể có ngoại lệ. Chọn một tiền tố sẽ là sai. Nếu có Arrays#toList, thì tôi hy vọng nó sẽ tạo ra một danh sách mới với một mảng bên dưới mới.
maaartinus

Tôi nghĩ Smalltalk đã phạm sai lầm ở đó, họ không hiểu quy ước. Đó là một quy ước khó hiểu (và thậm chí là thông báo) bởi vì nó rất trừu tượng và nó không đặc biệt có tác động. Ngay cả chính hành động đặt câu hỏi này cũng đòi hỏi một số hiểu biết.
usr

3
@usr Smalltalk có thể đã được thiết kế trước khi nó trở thành một hội nghị
Bergi

6

Mặc dù đã có một câu trả lời được chấp nhận, nó dường như tập trung vào C ++, trong khi câu hỏi được gắn thẻ java . Trong Java, ví dụ đầu tiên xuất hiện trong đầu cho loại điều này là Arrays.asList , trả về, về cơ bản, một khung nhìn của một mảng, được gói trong một danh sách. Các mảng cơ bản và danh sách vẫn được kết nối mặc dù; thay đổi đối với mảng được phản ánh trong danh sách và ngược lại. Tuy nhiên, mảng được trả về bởi phương thức toArray của danh sách độc lập với mảng ban đầu và từ danh sách:

String[] wordArray = {"one", "fine", "day"};
List<String> wordList = Arrays.asList(wordArray);

// changes to the array are visible in the list
System.out.println(wordList); // prints "[one, fine, day]"
wordArray[1] = "horrible";
System.out.println(wordList); // prints "[one, horrible, day]"

// changes to the list are visible in the array
wordList.set(1, "beautiful");
System.out.println(wordArray[1]); // prints "beautiful"

// but changes to the list or array don't affect the 
// result from the list's toArray method.
String[] moreWords = wordList.toArray(new String[] {});
wordList.set(0, "the");
wordArray[1] = "best";
for (int i=0; i<3; i++) {
  System.out.println(moreWords[i]); // prints "one", "beautiful", and "day"
}

Tất cả những gì đã nói, không có gì đảm bảo rằng mọi nhà phát triển thư viện đều tuân theo quy ước này, vì vậy bạn vẫn cần kiểm tra tài liệu để tìm hiểu xem đây có phải là hành vi bạn sẽ nhận được từ mã không xác định.

Một nơi khác mà tôi đã thấy là ... () phương thức được sử dụng thường xuyên là trong các kiểu hạ âm thành các kiểu phụ. Ví dụ: nếu bạn có một tập hợp các kiểu con, thì bạn có thể kết thúc bằng mã như:

  /**
   * Every Node is either an ANode or a BNode.
   */
  interface Node {

    /**
     * Returns this Node as an ANode.
     * 
     * @return this node
     */
    default ANode asANode() {
      if (this instanceof ANode) {
        return (ANode) this;
      }
      else {
        throw new UnsupportedOperationException();
      }
      // Or, in Java8 style, perhaps:
      // return Optional.of(this)
      //     .filter(ANode.class::isInstance)
      //     .map(ANode.class::cast)
      //     .orElseThrow(UnsupportedOperationException::new);
    }

    /**
     * Returns this Node as a BNode.
     * 
     * @return this node
     */
    default BNode asBNode() {
      if (this instanceof BNode) {
        return (BNode) this;
      }
      else {
        throw new UnsupportedOperationException();
      }
    }
  }

1

Sự khác biệt tôi nhận thấy (chỉ bây giờ bằng cách nghĩ về nó) là

  • Để thường chuyển đổi sang một loại tham chiếu khác (một đối tượng hơi phức tạp)
  • Như thường trả về một loại giá trị đơn giản

Vì vậy, chúng tôi thấy AsInteger và AsString và chúng tôi thấy ToArray và ToStringList.

Để ngụ ý một chuyển đổi, có ý nghĩa (đó là một phong trào, một quá trình). Như ngụ ý một đại diện, một cách thể hiện đối tượng ban đầu.

Một cách nhìn khác về điều này:

  • Để là một hoạt động, vì vậy bạn sẽ sử dụng nó cho các phương thức.
  • Là một đại diện đơn giản, vì vậy bạn sẽ sử dụng nó cho các thuộc tính.

Và sau đó là "nghệ thuật trước" (hoặc di sản) để giải quyết. Trước khi các ngôn ngữ hoàn toàn OO từ đầu, bạn sẽ có các hàm thư viện như StrToInt () và IntToStr (). Họ đã thực hiện chuyển đổi, họ là các hoạt động nên thật hợp lý khi gọi họ là SomethingToS Somethingelse (). Rốt cuộc, To hoạt động nhiều hơn As. Tôi đặc biệt nghĩ về Delphi ở đây.

Khi C # được thiết kế với tham vọng đi hết OO, sẽ có một phương thức trên đối tượng số nguyên bây giờ sẽ chuyển đổi số nguyên thành chuỗi. Mặc dù chúng ta cũng có một lớp Convert, việc chuyển đổi thành chuỗi rất phổ biến đến mức nó được tạo thành một phương thức ảo trên đối tượng. Các nhà thiết kế có thể đã hình dung rằng ToString sẽ quen thuộc hơn với mọi người từ mô hình cũ và có lẽ đây là lý do tại sao chúng ta có một phương thức ảo ToString () chứ không phải là một tài sản ảo AsString.


3
Thế còn toString()?
Ded repeatator

Bạn đã cho tôi ở đó. Tôi nghĩ AsString sẽ phù hợp hơn. Ibhave một số suy nghĩ bổ sung, tôi sẽ cập nhật câu trả lời của tôi.
Martin Maat

Tôi không nghĩ câu trả lời này thực sự hoàn thiện các quy ước trong C #. Ví dụ. Cả ToList () và AsEnumerable () đều trả về các đối tượng phức tạp, sự khác biệt là ToList () luôn trả về một đối tượng mới trong khi AsEnumerable () trả về một khung nhìn hoặc bộ điều hợp trên đối tượng ban đầu.
JacquesB

@JaquesB Rõ ràng những ý tưởng khác nhau đã được áp dụng ở đây và đó. Delphi có các thuộc tính AsInteger và AsString trên các đối tượng TField (đóng gói các trường cơ sở dữ liệu). Tôi có thể đã được thiên vị bởi điều này. Nhưng một lần nữa, câu hỏi được gắn thẻ với Java, không phải bằng C # hoặc Delphi.
Martin Maat
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.