Có thể đổi tên một phương thức bảo quản đóng gói?


9

Tôi đã đọc trang này , về thời điểm getters / setters là hợp lý và OP đã đưa ra mẫu mã sau:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

Các câu trả lời được chấp nhận trạng thái:

Bằng cách này, trong ví dụ của bạn, tôi sẽ cung cấp cho lớp Fridgecác putCheese()takeCheese()phương pháp, thay vì get_cheese()set_cheese(). Sau đó, bạn vẫn sẽ đóng gói.

Làm thế nào để đóng gói được bảo toàn bằng cách đổi tên nó từ get / set thành putCheese()/ takeCheese()Rõ ràng là bạn đang nhận / thiết lập một giá trị, vậy tại sao không chỉ đơn giản là để nó là get / set?

Trong cùng một câu trả lời, nó cũng ghi:

Có getters và setters không tự nó phá vỡ đóng gói. Điều gì đóng gói đóng gói là tự động thêm một getter và setter cho mọi thành viên dữ liệu (mọi trường, trong biệt ngữ java), mà không cho nó bất kỳ suy nghĩ nào.

Trong trường hợp này, chúng tôi chỉ có một biến, cheesevà bạn có thể muốn lấy và trả lại phô mai vào tủ lạnh, vì vậy một cặp get / set trong trường hợp này là hợp lý.


7
putCheesesẽ thêm phô mai vào tủ lạnh và takeCheesesẽ loại bỏ nó - đây là những trừu tượng hướng miền (cấp độ cao hơn), chứ không phải là getters & setters trường đối tượng (là trừu tượng lập trình máy tính (cấp độ thấp)).
Erik Eidt

Câu trả lời:


17

Tôi nghĩ rằng bạn đang bị mất điểm. Nó không nói rằng bạn nên đổi tên setter và getter, nhưng để có các phương thức thêm và loại bỏ các mục từ tủ lạnh. I E

public class Fridge
{
    private int numberOfCheeseSlices;

    public void AddCheeseSlices(int n)
    {
         if(n < 0) { 
             throw new Exception("you cant add negative cheese!");
         }
         if(numberOfCheeseSlices + n > this.capacityOfFridge) { 
             throw new Exception("TOO MUCH CHEESE!!");
         }
         ..etc
         this.numberOfCheeseSlices += n;
    }
}

Bây giờ biến riêng được đóng gói. Tôi không thể chỉ đặt nó thành bất cứ thứ gì tôi muốn, tôi chỉ có thể thêm và loại bỏ các lát phô mai từ tủ lạnh bằng các phương pháp, điều này đảm bảo rằng bất kỳ quy tắc logic kinh doanh phô mai nào tôi muốn đều được áp dụng.


2
Đúng, nhưng bạn vẫn có thể để nó như setCheese()có logic tương tự trong setter. Đối với tôi, dù sao đi nữa, bạn đang cố gắng che giấu sự thật bạn đang sử dụng một setter bằng cách đổi tên phương thức, nhưng rõ ràng là getter / thiết lập một cái gì đó.
QueenSvetlana

21
@QueenSvetlana nó không phải là một setter. Đó là một hoạt động. Bạn đang nói với tủ lạnh "đây là một loại phô mai khác" và nó đang thêm nó vào số lượng phô mai được đóng gói bên trong của nó. Một setter sẽ nói "bây giờ bạn có 5 pho mát." Đây là các hoạt động chức năng khác nhau, không chỉ tên khác nhau.
Ant P

1
bạn có thể gọi nó là setCheese, nhưng điều đó sẽ gây nhầm lẫn vì nó sẽ không đặt giá trị của phô mai.
Ewan

6
Lưu ý có một lỗi tràn số nguyên ở đây. Nếu đã có hơn 0 pho mát, AddCheese(Integer.MAX_VALUE)sẽ thất bại, nhưng sẽ không.
dùng253751

3
điều đó sẽ được bao phủ trong phần ..etc
Ewan

5

Theo định nghĩa, Getters và setters phá vỡ đóng gói mỗi lần , theo định nghĩa. Những gì có thể được tranh luận là đôi khi chúng ta cần phải làm điều đó. Ngoài ra, đây là câu trả lời của tôi:

Cách đóng gói được bảo toàn bằng cách đổi tên nó từ get / set thành putCheese () / TakeCheese () Rõ ràng bạn đang nhận / thiết lập một giá trị, vậy tại sao không đơn giản để nó là get / set?

Sự khác biệt là về ngữ nghĩa, nghĩa là những gì bạn viết. Đóng gói không chỉ là để bảo vệ, mà còn che giấu trạng thái nội bộ. Nhà nước nội bộ thậm chí không nên được biết đến bên ngoài, thay vào đó, đối tượng dự kiến ​​sẽ cung cấp các phương thức liên quan đến kinh doanh (đôi khi được gọi là "hành vi") để thao túng / sử dụng trạng thái đó.

Vì vậy, getsetlà các thuật ngữ kỹ thuật và dường như không liên quan gì đến miền "tủ lạnh", trong khi puttakethực sự có thể có ý nghĩa.

Tuy nhiên , cho dù puthoặc takelàm thực tế cảm giác vẫn còn phụ thuộc vào yêu cầu và không thể được đánh giá một cách khách quan. Xem điểm tiếp theo:

Trong trường hợp này, chúng tôi chỉ có một biến số, phô mai và bạn có thể muốn lấy và trả lại phô mai vào tủ lạnh, vì vậy một cặp get / set trong trường hợp này là hợp lý.

Điều đó không thể được xác định một cách khách quan mà không có thêm bối cảnh. Ví dụ của bạn chứa một go_shopping()phương thức ở nơi khác. Nếu đó là những gì Fridgedành cho, hơn là nó không cần gethoặc set, những gì nó cần là Fridge.go_shopping(). Bằng cách này, bạn có một phương thức xuất phát từ các yêu cầu, tất cả "dữ liệu" mà nó cần là cục bộ và bạn có hành vi thực tế thay vì chỉ là một cấu trúc dữ liệu được che giấu mỏng.

Hãy nhớ rằng, bạn không xây dựng một chung chung, có thể tái sử dụng Fridge. Bạn đang xây dựng một Fridgeyêu cầu của bạn mà thôi. Bất kỳ nỗ lực nào làm cho nó nhiều hơn những gì nó cần là thực sự lãng phí.


10
Getters and setters break encapsulation every single time- Đó là một từ quá mạnh mẽ theo sở thích của tôi. Các phương thức (bao gồm cả getters và setters) có cùng mục đích như các cổng thực hiện tại một buổi hòa nhạc: chúng cho phép ra vào có trật tự và thoát khỏi địa điểm.
Robert Harvey

8
"Getters và setters phá vỡ đóng gói mỗi lần, theo định nghĩa" - theo định nghĩa nào? Tôi cũng có một vấn đề với điều này, bởi vì getters và setters chỉ là một phần của giao diện công cộng, như bất kỳ thành viên nào khác; họ chỉ phá vỡ đóng gói nếu họ tiết lộ các chi tiết triển khai được coi là nội bộ theo thiết kế (nghĩa là theo quyết định của lập trình viên (hoặc một nhóm)). Thực tế là getters và setters thường được thêm vào một cách ngớ ngẩn, với điều khiển khớp nối là một suy nghĩ lại, là một vấn đề hoàn toàn khác.
Filip Milovanović

2
@ FilipMilovanović Điểm công bằng. Như tôi đã đề cập trong câu trả lời, "đóng gói" được sử dụng để ẩn nội bộ đối tượng (== object state == biến đối tượng). Getters và setters xuất bản nội bộ đối tượng. Do đó theo những định nghĩa này, chúng là xung đột vĩnh viễn. Bây giờ, cho dù đôi khi chúng ta cần phá vỡ đóng gói là một vấn đề khác, cần được xử lý riêng. Để rõ ràng, bằng cách nói rằng setters / getters luôn phá vỡ đóng gói Tôi không nói nó luôn luôn "sai", nếu điều đó có ích.
Robert Bräutigam

5
getters và setters không "phá vỡ đóng gói theo nghĩa đen luôn luôn". Getters và setters thường thậm chí không đề cập đến các thành viên bên dưới trực tiếp, thực hiện một số loại hoạt động hoặc chỉ được xác định riêng, bạn chỉ có thể có một getter hoặc chỉ có thể có một setter. Nó phá vỡ đóng gói khi getters và setters không làm gì hơn là truy cập thành viên và cả hai đều được xác định cho cùng một trường. Thậm chí điều này có thể cần thiết cho những người bảo trì thư viện, những người không muốn phá vỡ ABI / API bằng các thay đổi bên trong và tránh việc biên dịch lại máy khách.
whn

4
Ok, getters và setter chỉ phá vỡ đóng gói 99% thời gian. Vui mừng? Và, bằng cách phơi bày loại đối tượng được đóng gói, họ chắc chắn phá vỡ đóng gói. public int getFoo()Trong thực tế, một khi bạn đã có một điều gần như không thể, để thay đổi sang loại khác.
user949300

3

Hầu như tất cả những điều này cho thấy một sự hiểu lầm cơ bản về đóng gói, và cách nó được áp dụng.

Phản hồi ban đầu rằng bạn đã phá vỡ đóng gói chỉ là sai. Ứng dụng của bạn có thể chỉ cần đặt giá trị của phô mai trong tủ lạnh thay vì tăng / giảm hoặc thêm / loại bỏ. Ngoài ra, nó không phải là ngữ nghĩa, bất kể bạn gọi nó là gì, nếu bạn có nhu cầu truy cập và / hoặc thay đổi các thuộc tính bạn không phá vỡ đóng gói bằng cách cung cấp chúng. Cuối cùng, đóng gói không thực sự là "ẩn", đó là về việc kiểm soát quyền truy cập vào trạng thái và các giá trị không cần phải công khai hoặc thao túng bên ngoài lớp, trong khi cấp nó cho những người nên và thực hiện nhiệm vụ có sẵn trong nội bộ.

Một getter hoặc setter không phá vỡ đóng gói khi có nhu cầu chính đáng để nhận hoặc đặt giá trị. Đây là lý do tại sao các phương pháp có thể được công khai.

Đóng gói là về việc giữ dữ liệu và các phương thức sửa đổi dữ liệu đó trực tiếp với nhau ở một nơi logic, lớp.

Trong trường hợp cụ thể này, rõ ràng cần phải thay đổi giá trị của phô mai trong ứng dụng. Bất kể việc này được thực hiện như thế nào, thông qua get / set hoặc add / remove, miễn là các phương thức được gói gọn trong lớp bạn đang theo kiểu hướng đối tượng.

Để làm rõ, tôi sẽ đưa ra một ví dụ về cách đóng gói bị phá vỡ bằng cách cung cấp quyền truy cập bất kể tên phương thức hoặc thực thi logic.

Giả sử tủ lạnh của bạn có "trọn đời", chỉ cần một số tiếng tích tắc trước khi tủ lạnh không còn hoạt động (vì lý do tranh luận, tủ lạnh không thể được sửa chữa). Về mặt logic, không có cách nào người dùng (hoặc phần còn lại của ứng dụng của bạn) có thể thay đổi giá trị này. Nó nên là riêng tư. Nó sẽ chỉ được hiển thị thông qua nói một thuộc tính công khai khác được gọi là "isWorking". Khi hết thời gian sử dụng, bên trong bộ tủ lạnh sẽ làm việc sai.

Việc thực hiện đếm ngược thời gian và lật công tắc isWorking hoàn toàn bên trong tủ lạnh, không có gì bên ngoài có thể / nên có thể thực hiện quy trình. isWorking chỉ nên được nhìn thấy, do đó, một getter không phá vỡ đóng gói. Tuy nhiên, việc thêm các phụ kiện cho các yếu tố của quy trình trọn đời sẽ phá vỡ sự đóng gói của bạn.

Giống như hầu hết mọi thứ, định nghĩa của đóng gói không theo nghĩa đen, nó tương đối. Bạn có thể thấy X bên ngoài lớp học không? Bạn có thể thay đổi Y? Là tất cả mọi thứ áp dụng cho đối tượng của bạn ở đây trong lớp này hay là chức năng trải đều trên nhiều lớp?


Hãy nhìn vào nó một cách thực tế. Bạn đang nói đóng gói không bị phá vỡ nếu mã được dự định theo cách đó hoặc nếu có lý do "hợp pháp". Điều đó về cơ bản có nghĩa là chúng ta không bao giờ có thể nói đóng gói bị hỏng, bởi vì nhà phát triển chỉ phải nói rằng cô ấy "dự định" theo cách đó, hoặc có một lý do "hợp pháp". Vì vậy, định nghĩa này về cơ bản là vô dụng, phải không?
Robert Bräutigam

Không, tôi nói đóng gói không bị phá vỡ chỉ bằng cách cung cấp quyền truy cập. Và nó không liên quan gì đến những gì một lập trình viên nói, nhưng nhu cầu của ứng dụng là gì. Một ứng dụng cần có quyền truy cập để thao tác các đối tượng, đóng gói là về kiểm soát truy cập. Một ứng dụng có thể cần "thiết lập" một thuộc tính của một đối tượng, nhưng logic và hoặc các tính toán cần thiết để thực hiện thao tác "set" đó phải được gói gọn trong lớp đối tượng.
dùng343330

Tôi nghĩ rằng đây là nơi chúng ta khác nhau về cơ bản, bạn nói: "Một ứng dụng có thể cần phải" thiết lập "một thuộc tính của một đối tượng ...". Tôi không nghĩ vậy. Chọn một thiết kế liên quan đến việc thiết lập hoặc nhận một thuộc tính là tùy thuộc vào nhà phát triển. Đó là một sự lựa chọn! Có rất nhiều cách để mã hóa một cái gì đó, không phải tất cả những cách liên quan đến việc nhận hoặc thiết lập các giá trị biến thể hiện.
Robert Bräutigam

Có thể ... Thông thường thiết kế dựa trên việc đáp ứng nhu cầu, cho dù được chọn bởi lập trình viên hay không dựa trên môi trường kinh doanh. Trong cả hai trường hợp, nếu ứng dụng có nhu cầu cơ bản để thao tác một giá trị là một phần của đối tượng, thì bạn phải làm cho chức năng đó có thể truy cập theo một cách nào đó. Cung cấp một điểm vào để làm công việc không phá vỡ đóng gói. Lấy một ứng dụng bán hàng. Tại một số điểm, giao dịch của bạn sẽ tính thuế, thực hiện điều đó trong đối tượng giao dịch sẽ giữ cho nó được đóng gói, nhưng ứng dụng sẽ có thể nêu giao
dịch.CalcTax

Setters là những ví dụ tồi vì tính đơn giản của chúng, hãy nghĩ về một hàm làm việc nhiều hơn dẫn đến một thuộc tính đối tượng được cập nhật so với một cái gì đó bên ngoài lớp đang thực hiện công việc và sau đó nói object.attribution = x. Thứ nhất là đóng gói tốt trong khi cung cấp quyền truy cập phù hợp, thứ hai thì không. Đối với getters, ứng dụng có cần chỉ biết phần đó của một đối tượng để làm một cái gì đó không thể chứa trong lớp đối tượng không? nếu có, phơi bày nó không phá vỡ đóng gói của bạn. nếu không, thì gói nó trong lớp đối tượng
user343330

1

Nó không chỉ đổi tên một phương thức. Hai phương thức hoạt động khác nhau.

(Hình ảnh này trong tâm trí của bạn)

get_cheese và set_cheese phơi phô mai. putCheese () và TakeCheese () giữ phô mai ẩn và chăm sóc việc quản lý nó và cung cấp cho người dùng một cách để xử lý nó. Người quan sát không nhìn thấy pho mát, anh ấy / cô ấy chỉ nhìn thấy hai phương pháp thao tác với 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.