2013-08-03 36 views
6

Thực hành thiết kế chung là đặt các biến cá thể riêng tư và có các getters và setters công khai để truy cập chúng. Nhưng nhiều lần tôi đã thấy các mẫu mã trên internet có các hàm tạo gán các giá trị trực tiếp cho biến cá thể riêng thay vì sử dụng các bộ định vị bên trong các hàm tạo. Tui bỏ lỡ điều gì vậy?Các trường riêng tư cài đặt Java bên trong các nhà xây dựng

public class Person{ 
    private String name; 

    public Person(String name){ 
     //is this right, seems like the whole encapsulation purpose is defeated 
     this.name = name; 

     //shouldn't this be used 
     setName(name); 
    } 

    public String getName(){ 
     return this.name; 
    } 

    public void setName(String name){ 
     this.name = name; 
    } 
} 
+7

Tôi tin rằng mục đích của việc biến các biến là riêng biệt là cô lập chúng khỏi thao tác trực tiếp từ ** các lớp ** khác. –

+2

ngoài ra, từ khóa 'this' này không bắt buộc đối với getter; nó chỉ được sử dụng khi có sự mơ hồ (nghĩa là nếu có một biến khác gọi là "tên" trong cùng phạm vi) – ataulm

Trả lời

5

Bạn không bỏ sót bất cứ điều gì. Những gì bạn làm phụ thuộc hoàn toàn vào hoàn cảnh của bạn. Tuy nhiên, hãy xem xét điều này:

Việc xác thực thông số trong trình thiết lập là rất phổ biến.Ví dụ, giả sử tôi có một lớp học với lĩnh vực có thể chứa một giá trị từ 0 đến 10 (các "ném" là không cần thiết cho các ngoại lệ gõ bên dưới nhưng tôi bao gồm nó cho rõ ràng):

public class Example { 
    private int value; 
    public Example() { 
    } 
    public final int getValue() { 
     return value; 
    } 
    public final void setValue (int value) throws IllegalArgumentException { 
     if (value < 0 || value > 10) 
      throw new IllegalArgumentException("Value is out of range."); 
    } 
} 

Ở đây, setValue () xác nhận 'giá trị' để đảm bảo giá trị đó tuân thủ các quy tắc. Chúng tôi có một bất biến cho biết "một ví dụ sẽ không tồn tại với một giá trị ngoài phạm vi". Bây giờ chúng ta hãy nói rằng chúng ta muốn tạo một hàm tạo có giá trị. Bạn có thể làm điều này:

public class Example { 
    ... 
    public Example (int value) { 
     this.value = value; 
    } 
    ... 
} 

Như bạn thấy, có sự cố. Ví dụ mới (11) sẽ thành công, và bây giờ một ví dụ tồn tại phá vỡ các quy tắc của chúng ta. Tuy nhiên, nếu chúng ta sử dụng setter trong các nhà xây dựng, chúng ta có thể thuận tiện thêm tất cả các xác nhận tham số để các nhà xây dựng cũng như:

public class Example { 
    ... 
    public Example (int value) throws IllegalArgumentException { 
     setValue(value); // throws if out of range 
    } 
    ... 
} 

Vì vậy, có rất nhiều lợi ích này.

Bây giờ, vẫn có những trường hợp bạn có thể muốn chỉ định giá trị trực tiếp. Đối với một, có thể bạn không có setters (mặc dù tôi cho rằng việc tạo private hoặc package setters riêng vẫn là điều mong muốn, vì những lý do đã đề cập ở trên, để hỗ trợ phản ánh/bean nếu cần thiết và dễ dàng xác nhận trong mã phức tạp hơn).

Một lý do khác có thể là bạn có một nhà xây dựng biết, bằng cách nào đó, trước thời hạn giá trị hợp lệ sẽ được chỉ định và do đó không cần xác thực và có thể gán biến trực tiếp. Điều này thường không phải là một lý do thuyết phục để bỏ qua bằng cách sử dụng setters mặc dù. Tuy nhiên, tất cả-trong-tất cả, nó thường là một ý tưởng tốt để sử dụng các setters ở khắp mọi nơi khi có thể, nó thường sẽ dẫn đến sạch hơn và rõ ràng hơn code đó là dễ dàng hơn để duy trì như tăng phức tạp. Các tính năng:.

Hầu hết các ví dụ bạn thấy nơi mọi người đặt biến trực tiếp chỉ là người "lười" - hoàn toàn có thể chấp nhận được nếu tình huống đảm bảo (có thể bạn đang viết chương trình hoặc ứng dụng thử nghiệm nhanh và không muốn thực hiện một loạt các setters, ví dụ). Không có gì sai với điều đó miễn là bạn giữ cho hình ảnh lớn trong tâm trí và chỉ được "lười biếng" khi nó thích hợp. Một điều tôi muốn thêm dựa trên một số câu trả lời khác ở đây: Nếu bạn ghi đè lên một setter trong một phân lớp, và dữ liệu bạn đang thiết lập phá vỡ bất biến mà lớp cơ sở thừa nhận, sau đó hoặc các setters có liên quan nên được thực hiện cuối cùng hoặc lớp cơ sở không nên đưa ra những giả định đó. Nếu các bộ định vị ghi đè phá vỡ các biến thể lớp cơ sở thì có một vấn đề lớn hơn trong tầm tay.

Bạn sẽ nhận thấy trình gỡ rối/bộ đặt là cuối cùng trong ví dụ trên. Điều này là do quy tắc của chúng tôi là "bất kỳ Ví dụ nào phải có giá trị từ 0 đến 10". Quy tắc này do đó mở rộng đến các lớp con. Nếu chúng ta không có quy tắc đó và nếu một ví dụ có thể lấy bất kỳ giá trị nào, thì chúng ta sẽ không cần một setter cuối cùng và có thể cho phép các lớp con ghi đè.

Hy vọng điều đó sẽ hữu ích.

+0

Đã thêm nhận xét ở cuối về các người định cư bị ghi đè. –

0

Biến đặt thành riêng tư là khuyến khích đóng gói từ các lớp khác.

Trừ khi setName(String) có nghĩa là thực hiện điều gì đó bổ sung (tên phương thức không ngụ ý), không cần thiết phải sử dụng setter khi bạn đang ở trong lớp có biến riêng tư.

+1

Điều này không * hoàn toàn đúng, vì bạn có thể đóng gói tất cả logic xác thực của mình trong trình thiết lập và do đó có các dịch vụ xác thực từ nơi khác trong lớp của bạn. –

+0

+1 chắc chắn, đã đồng ý. – ataulm

0

này không đánh bại đóng gói từ các thành viên tư nhân vẫn ẩn từ các lớp khác

Nếu phương pháp sửa đổi không chứa bất kỳ logic và chỉ đặt thành viên thì không có sự khác biệt giữa trực tiếp thiết lập các thành viên gọi phương pháp setter của nó mặc dù để thực hành tốt hơn setter nên được gọi.

Thiết lập cho biết tên của người này có thể thay đổi trong tương lai và cho phép dễ dàng mà không cần tạo lại toàn bộ đối tượng người.

2

Thỉnh thoảng khi bạn muốn làm cho lớp không thay đổi được, đó chỉ là một trong những điều bạn cần làm. Và không có phương pháp setter ở tất cả trong trường hợp đó.

+0

Có một lý lẽ, chủ yếu là về việc xác nhận, thay vì có người định cư riêng. Nhưng điều này là rất đúng, đôi khi bạn chỉ muốn đặt cùng một mã đơn giản một cách nhanh chóng, và nó là bất tiện để tạo ra setters tư nhân với rất ít lợi ích. –

0

các biến tin có thể truy cập trực tiếp bất cứ nơi nào trong lớp

settng variabels tin là để đóng gói chúng từ các lớp khác

2

Tùy thuộc vào bối cảnh, việc sử dụng các getter và setter thực sự là một sự vi phạm lớn hơn đóng gói hơn là sử dụng các biến thành viên trong các hàm tạo. Nếu bạn muốn đặt biến thành viên 'tên' của lớp này, một trong các cách tiếp cận này sẽ hoạt động vì việc xây dựng bị ẩn khỏi người gọi và do đó không vi phạm đóng gói. Một cảnh báo là việc sử dụng setName trong hàm tạo có thể gọi một phương thức ghi đè trong một lớp con có thể không phải là thứ bạn muốn (vì nó có thể để lại tên không xác định trong lớp cha).

Dưới đây là một câu hỏi tương tự như của bạn mà có thể cung cấp cái nhìn sâu sắc thêm:

calling setters from a constructor

0

biến khởi tạo bên trong constructor là một thực tế rất phổ biến. Nó có thể được sử dụng để gán các giá trị cho các biến dựa trên người sử dụng constructor nào đã gọi. Bạn không thể viết mã dựa trên giả định rằng mã máy khách sẽ gọi phương thức setter để gán giá trị cho các biến mẫu. Luôn luôn gán giá trị mặc định cho biến khi đối tượng của nó được tạo (tức là bên trong hàm tạo).

Có sự khác biệt giữa việc khởi tạo biến trong hàm tạo và đặt giá trị khác nhau theo yêu cầu của mã gọi (sử dụng phương thức setter). Cả hai đều có mục đích khác nhau và các mục tiêu khác nhau.

+0

Tôi không nghĩ rằng điều này trả lời câu hỏi (** hoặc có lẽ tôi hiểu lầm **). OP không hỏi liệu nó có thích hợp để khởi tạo các biến trong constructor khi bạn đã cung cấp các setters hay không; thay vào đó, OP đang hỏi về _use_ của những người định cư đã nói từ bên trong nhà xây dựng. – ataulm

0

Điều này hoàn toàn bình thường. Một số biến có thể cần phải được khởi tạo ngay khi đối tượng được tạo, do đó rất có ý nghĩa khi truyền chúng trong hàm tạo và nhiều lần chúng ta có thể không muốn cung cấp các biến cho các biến đó để tránh thay đổi các giá trị sau khi đối tượng được tạo.

+0

Có một đối số, chủ yếu liên quan đến việc xác thực (đặc biệt là đối với các biến có thể được đặt ở nhiều nơi), thay vì phải có các trình cài đặt riêng. Nhưng điều này là rất đúng, đôi khi bạn chỉ muốn đặt cùng một mã đơn giản một cách nhanh chóng, và nó là bất tiện để tạo ra setters tư nhân với rất ít lợi ích. –

0

Được phép gán trực tiếp các giá trị có trong setter lớp được cung cấp không thực hiện bất kỳ quá trình xử lý nào khác.

Về cơ bản setters/getters được sử dụng để cung cấp truy cập hạn chế đến dữ liệu cá nhân như trở về bản sao của dữ liệu thay vì tham chiếu của đối tượng tư nhân, xác nhận dữ liệu trong getter vv ..

Kể từ khi các nhà xây dựng là một phần của đối tượng chính nó, và chúng tôi chắc chắn những gì chúng tôi đang làm là đúng, sau đó ok của nó.

+0

Thật đáng để chỉ ra rằng câu lệnh then chốt ở đây là "và chúng tôi chắc chắn những gì chúng tôi đang làm là đúng". Nếu bạn đã từng áp đặt các quy tắc về giá trị của các trường, đừng quên cẩn thận để đảm bảo rằng hàm tạo không vi phạm các quy tắc đó. –

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