2008-08-28 29 views
18

Tôi đã đề xuất điều này trong my blog, nhưng tôi thấy địa điểm này là phù hợp nhất.Thiết kế: Java và trả về tự tham chiếu trong các phương thức setter

Đối với các lớp có danh sách các bộ định cư được sử dụng thường xuyên, tôi thấy cách này rất hữu ích (mặc dù gần đây tôi đã đọc về Builder pattern trong Java hiệu quả tương tự). Về cơ bản, tất cả các phương pháp setter trả lại đối tượng riêng của mình như vậy thì bạn có thể sử dụng mã như thế này:

MyClass 
    .setInt(1) 
    .setString("test") 
    .setBoolean(true) 
    ; 

Setters chỉ đơn giản là trở lại này cuối cùng:

public MyClass setInt(int anInt) { 
    [snip] 
    return this; 
    } 

ý kiến ​​của bạn là gì? Những ưu và khuyết điểm là gì? Điều này có ảnh hưởng đến hiệu suất không?

+1

+ 1 Ý tưởng tuyệt vời. – helpermethod

Trả lời

13

@pek
Yêu cầu xích lại là một trong các đề xuất cho Java 7. Nó nói rằng nếu kiểu trả về bị hủy, thì nên hoàn trả lại số này. Nếu bạn quan tâm đến chủ đề này, có một loạt các liên kết và một ví dụ đơn giản trên Alex Miller's Java 7 page.

+0

Tôi thấy thành ngữ này có thể là một ý tưởng hay (mặc dù tôi sẽ không sử dụng nó), nhưng tại sao mở rộng ngôn ngữ nếu nó có thể được thực hiện bằng cách khai báo rõ ràng kiểu trả về của các setters không bị vô hiệu? Tôi không thích ý tưởng của các phần mở rộng đặc biệt đến một ngôn ngữ để hỗ trợ các thành ngữ cụ thể. – Giorgio

+1

Tôi đồng ý với @Giorgio. Đây là hành vi "ma thuật", và mọi phép thuật đều xấu. Đó là phép thuật trong ý nghĩa rằng bạn không thể kiểm tra nguồn để tìm ra những gì nó trả về, bạn phải _know_ rằng void trả về một tham chiếu tự ... Tôi muốn họ giới thiệu một kiểu trả về mới cho điều này ... 'thay vì' void '. Hoặc một cái gì đó. –

+0

@Tor Valamo: Tôi đồng ý với bạn. Thêm vào đó, tôi nghĩ rằng một ngôn ngữ lập trình nên cung cấp ** khái niệm ** không ** thành ngữ **. Nếu người ta thực sự muốn sử dụng nhiều thành ngữ, người ta nên sử dụng một ngôn ngữ mở rộng như Lisp, nhưng người ta không thể mong đợi rằng một ngôn ngữ được tiếp tục mở rộng để hỗ trợ tất cả các thành ngữ có thể có: có rất nhiều ngôn ngữ có thể dễ dàng trở thành (không cần thiết) . – Giorgio

2

Tôi sẽ không tự làm điều đó, bởi vì với tôi nó làm mờ những gì một phương pháp cụ thể làm, và phương pháp-chuỗi là sử dụng hạn chế với tôi hơn làm nó lâu dài. Nó không phải là sẽ gửi cho tôi vào một bóng run rẩy của cơn thịnh nộ và rối loạn tâm thần, mặc dù, mà luôn luôn là một điều tốt. : ')

Tôi sẽ không quan tâm đến hiệu suất; chỉ cần hỏi Knuth.

8

Đây được gọi là Fluent Interface, để tham khảo.

Cá nhân, tôi nghĩ rằng đó là một ý tưởng khá gọn gàng, nhưng một vấn đề về hương vị thực sự. Tôi nghĩ rằng jQuery hoạt động theo cách này.

-2

Tôi đồng ý với @Bernard rằng phương thức xâu chuỗi như thế này là mục đích của những người định cư. Thay vào đó tôi sẽ đề nghị rằng nếu bạn luôn được tạo ra chuỗi setters như thế này bạn nên tạo một Constructor tùy chỉnh cho lớp học của bạn nên thay vì

MyClass 
    .setInt(1) 
    .setString("test") 
    .setBoolean(true) 
    ; 

Bạn làm

new MyClass(1,"test",true); 

này làm cho nó dễ đọc hơn và bạn có thể sử dụng điều này để làm cho lớp của bạn không thay đổi được nếu bạn chọn.

+6

Trên thực tế, điều này làm cho nó nhiều, MUCH ít có thể đọc được nếu bạn có một số lượng lớn các setters và có rất nhiều biến thể trong đó những cái bạn cần phải gọi. Cố gắng xử lý điều đó với các nhà xây dựng quá tải sẽ là một cơn ác mộng, hãy tin tôi đi. –

+1

Tôi không đồng ý. Các nhà xây dựng chỉ nên có các tham số cho những gì được yêu cầu tại thời điểm tạo. Các nhà xây dựng để thuận tiện là bù đắp cho việc thiếu một cấu trúc phù hợp để xử lý cùng ngữ nghĩa. –

+0

Nhà thầu gây ô nhiễm là một ý tưởng tồi, trừ khi bạn có, nói hai hoặc ba tham số, ngọn. Gửi bất kỳ thứ gì cuối cùng cho các nhà xây dựng và sử dụng các trình cài đặt cho các trường có thể thay đổi. – Ajax

1

Tôi tìm thấy điều này là trong phong cách kém khi sử dụng trong setters. lớp học bất biến thường phù hợp hơn cho loạt, chẳng hạn như:

aWithB = myObject.withA(someA).withB(someB); 

nơi myObject là của lớp này:

class MyClass { 
    withA(TypeA a) { 
     this.a.equals(a) ? this : new MyClass(this, a); 
    } 

    private MyClass(MyClass copy, TypeA a) { 
     this(copy); 
     this.a = a; 
    } 
} 

Các mô hình xây dựng cũng rất hữu ích, vì nó cho phép các đối tượng cuối cùng là bất biến trong khi ngăn chặn các trường hợp trung gian bạn thường phải tạo khi sử dụng kỹ thuật này.

0

Tôi sử dụng làm người hâm mộ thực hành Java (và tệ hơn C#) để tạo ra các getters và setters (lấy các thuộc tính thiết lập) trong toàn bộ đối tượng. Điều này được sử dụng để được những gì tôi coi là đối tượng theo định hướng, nhưng thực sự điều này dẫn chúng tôi chỉ để lộ gan và thực hiện các đối tượng và không thực sự tận dụng lợi thế của đóng gói. Có những lúc bạn không thể thoát khỏi điều này (OR/M đến với tâm trí), nhưng nói chung đối tượng nên được thiết lập và sau đó thực hiện chức năng của nó. Các đối tượng mơ ước của tôi có xu hướng có một hoặc hai nhà xây dựng, và có thể một tá tá chức năng hoạt động.

Lý do cho điều này là khi tôi bắt đầu phát triển API, có một nhu cầu thực sự để giữ mọi thứ đơn giản. Bạn thực sự chỉ muốn thêm nhiều phức tạp như được yêu cầu để hoàn thành công việc, và getters và setters, trong khi đơn giản trong bản thân, thêm sự phức tạp trong đống khi được thêm vào hàng loạt. Điều gì sẽ xảy ra khi tôi tải setters i na thứ tự khác nhau? Anythign khác? Bạn có chắc không?

0

@Dan một lần nữa, đối với các tình huống phức tạp hơn (tính bất biến đến trong tâm trí) Mô hình Builder là một giải pháp tuyệt vời.

Ngoài ra, tôi đồng ý với bạn chủ yếu là trong getters. Tôi tin rằng những gì bạn đang nói là chủ yếu tuân theo mô hình "Tell don't ask" và tôi rất đồng ý. Nhưng đó là định hướng chủ yếu tại getters.

Cuối cùng, tất cả những điều trên đều dành cho các lớp học có nhiều thuộc tính. Tôi không thấy lý do cho bất kỳ điều gì nếu bạn chỉ có ít hơn, ví dụ: 7.

0

Tôi đã thực hiện điều này rất nhiều khi làm việc với thư viện excel POI của Apache; Tôi đã kết thúc bằng cách viết các phương thức trợ giúp bị xích để tôi có thể áp dụng định dạng, kiểu dữ liệu, dữ liệu ô nội bộ, công thức và định vị ô.

Đối với những thứ có nhiều phần tử nhỏ bé nhỏ cần phải có các tinh chỉnh nhỏ gọn, được áp dụng, nó hoạt động khá tốt.

1

Điều này có ý nghĩa đối với người xây dựng, nơi mà tất cả những gì bạn định làm là đặt tải nội dung, tạo đối tượng thực và ném người xây dựng. Đối với các nhà xây dựng, bạn cũng có thể loại bỏ phần "đặt" của tên phương thức. Tương tự như vậy, các loại bất biến không thực sự cần "nhận".

Something thing = new SomethingBuilder() 
    .aProperty(wotsit) 
    .anotherProperty(somethingElse) 
    .create(); 

Một mẹo hữu ích (nếu bạn không nhớ một chi phí thời gian chạy ~ 2K mỗi lớp) là sử dụng cú đúp thành ngữ kép:

JFrame frame = new JFrame("My frame") {{ 
    setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
    setLocation(frameTopLeft); 
    add(createContents()); 
    pack(); 
    setVisible(true); 
}}; 
+0

Đó không phải là "thành ngữ". Đó là một sự lạm dụng khủng khiếp của các lớp vô danh mà không trở thành chấp nhận được chỉ vì bạn cho nó một cái tên đẹp. –

+1

Đó là một thành ngữ. Nó làm cho code ít lộn xộn hơn. Nó sẽ làm cho tôi cho đến khi tôi đang sử dụng một ngôn ngữ có thể thể hiện rõ ràng hơn. –

+0

+1: hai điểm tốt. tại sao downvote? anh ta đã liệt kê cảnh báo về chi phí thời gian chạy. –

0

Làm thế nào để sử dụng

/** 
* 
* @author sanjay 
*/ 
public class NewClass { 
private int left ; 
private int top; 
public void set(int x,int y) 
    { 
    left=x; 
    top=y; 
} 
public NewClass UP(int x) 
    { 
    top+=x; 
    return this; 
} 
public NewClass DOWN(int x) 
    { 
    top-=x; 
    return this; 
} 
public NewClass RIGHT(int x) 
    { 
    left+=x; 
    return this; 
} 
public NewClass LEFT(int x) 
    { 
    left-=x; 
    return this; 
} 
public void Display() 
    { 
    System.out.println("TOP:"+top); 
    System.out.println("\nLEFT\n:"+left); 
} 
} 
public static void main(String[] args) { 
    // TODO code application logic here 
    NewClass test = new NewClass(); 
    test.set(0,0); 
    test.Display(); 
    test.UP(20).UP(45).DOWN(12).RIGHT(32).LEFT(20); 
    test.Display(); 
+0

Câu trả lời này dường như không giải quyết được các câu hỏi ban đầu của OP. –

Các vấn đề liên quan