Làm thế nào là đóng gói được sử dụng cho an toàn?


8

Tôi đang học OOP. Tôi đã nghiên cứu nhiều về đóng gói nhưng càng đọc tôi càng thấy bối rối.

Tôi hiểu rằng chúng tôi ẩn (bằng cách tạo dữ liệu riêng tư) và hiển thị nó cho người dùng của lớp (nhà phát triển khác) dưới dạng các thuộc tính hoặc phương thức. Tôi cũng hiểu bằng cách đóng gói chúng tôi ẩn chi tiết.

Trong một bài viết (http://www.csharp-station.com/Tutorial/CSharp/lesson19) tôi đã đọc:

Tóm tắt từ bài viết

Khi thiết kế một đối tượng, bạn phải suy nghĩ về cách người khác có thể sử dụng nó. Trong trường hợp tốt nhất, bất kỳ chương trình nào sử dụng đối tượng sẽ được thiết kế tốt và mã sẽ không bao giờ thay đổi. Tuy nhiên, thực tế là các chương trình thay đổi thường xuyên và trong môi trường nhóm, nhiều người chạm vào cùng một mã lúc này hay lúc khác. Do đó, nó có lợi để xem xét những gì có thể đi sai cũng như hình ảnh nguyên sơ như thế nào đối tượng nên được sử dụng.

Trong trường hợp đối tượng BankAccount, hãy kiểm tra tình huống mã bên ngoài đối tượng của bạn có thể truy cập vào trường Số tiền thập phân hoặc trường chuỗi Tên khách hàng. Tại thời điểm mã được viết, mọi thứ sẽ hoạt động tốt. Tuy nhiên, sau này trong chu kỳ phát triển, bạn nhận ra rằng đối tượng BankAccount nên theo dõi một ID khách hàng chứ không phải chuỗi Tên khách hàng vì bạn không muốn sao chép mối quan hệ giữa thông tin (hoặc một số lý do hợp lệ khác để thay đổi định nghĩa về trạng thái nội bộ) . Những thay đổi như vậy gây ra hiệu ứng gợn sóng trong mã của bạn vì nó được xây dựng để sử dụng lớp BankAccount, như được thiết kế ban đầu (với CustomerName là một chuỗi) và bây giờ bạn phải thay đổi mã truy cập trạng thái đó trong toàn bộ ứng dụng của bạn.

Nguyên tắc Encapsulation hướng đối tượng giúp tránh các vấn đề như vậy, cho phép bạn ẩn trạng thái nội bộ và truy cập trừu tượng vào nó mặc dù các thành viên kiểu như phương thức, thuộc tính và bộ chỉ mục. Đóng gói giúp bạn giảm sự ghép nối giữa các đối tượng và tăng khả năng duy trì mã của bạn.

Câu hỏi Làm thế nào đóng gói sẽ giúp khi thực hiện các thay đổi trong mã và từ các hiệu ứng gợn sóng của nó. Đối với một thành viên dữ liệu, nếu tôi thay đổi kiểu của nó từ int thành float, (ngay cả khi tôi phơi bày điều này bằng cách sử dụng thuộc tính), tôi sẽ cần thay đổi loại biến mà tôi đang sử dụng đã sử dụng mã này.

Vui lòng hướng dẫn cho tôi cách đóng gói sẽ giúp với những thay đổi như vậy.

Cảm ơn sự giúp đỡ và hướng dẫn này.

Câu trả lời:


8

Làm thế nào sẽ đóng gói giúp khi thực hiện các thay đổi trong mã và từ các hiệu ứng gợn sóng của nó. Đối với một thành viên dữ liệu, nếu tôi thay đổi kiểu của nó từ int thành float, (ngay cả khi tôi đang phơi bày điều này bằng cách sử dụng thuộc tính), tôi sẽ cần thay đổi loại biến mà tôi đang sử dụng đã sử dụng mã này.

Lợi ích của việc đóng gói là cho phép bạn thay đổi triển khai nội bộ mà không vi phạm mã máy khách. Nó không bảo vệ bạn nếu bạn quyết định rằng bạn cần thay đổi giao diện thành mã của mình, nhưng đó là một vấn đề khác.

Ví dụ: Giả sử bạn có một giá trị đại diện cho giá trên mỗi đơn vị của một số mặt hàng. Giá được biểu thị bằng xu và vì bạn không giao dịch bằng xu phân số nên bạn đã quyết định biến tài sản thành số nguyên (Tôi sẽ sử dụng C ở đây vì tôi không quen lắm với C #):

int _price

int pricePerUnit(void) {
    return _price;
}

int priceForUnits(int units) {
    return units * _price;
}

Tất cả đều ổn cho đến một ngày khi ai đó nhận thấy rằng công ty của bạn đang mất rất nhiều tiền do lỗi làm tròn số. Nhiều mặt hàng mà bạn theo dõi được mua và bán với số lượng nhiều nghìn đơn vị, vì vậy bạn cần bắt đầu theo dõi giá đến độ chính xác ít nhất là 0,001 cent. Vì bạn đủ thông minh để đóng gói giá thay vì cho phép khách hàng truy cập trực tiếp vào nó, bạn có thể thực hiện thay đổi đó khá nhanh:

double _dprice

int pricePerUnit(void) {
    return (int)_dprice;
}

int priceForUnits(int units) {
    return (int)(units * _dprice);
}

Giao diện mà khách hàng sử dụng để có được giá vẫn giữ nguyên, nhưng dữ liệu họ nhận được bây giờ chính xác hơn. Nếu giá mỗi đơn vị là $ 1,001, priceForUnits(1000000)bây giờ sẽ trả lại một mức giá lớn hơn $ 1000 so với trước đây. Điều đó xảy ra ngay cả khi bạn chưa thay đổi giao diện cho hệ thống của mình và do đó bạn chưa phá vỡ bất kỳ mã máy khách nào.

Bây giờ, đó có thể không phải luôn luôn là tất cả những gì bạn cần làm. Đôi khi, bạn sẽ cần thay đổi hoặc tăng cường giao diện của mình để bạn cũng có thể báo cáo giá chính xác hơn cho khách hàng:

double pricePerUnit() {
    return _dprice;
}

Một thay đổi như thế sẽ phá vỡ mã máy khách, vì vậy thay vào đó bạn có thể giữ giao diện cũ và cung cấp một thói quen mới hơn, tốt hơn:

int pricePerUnit() {
    return (int)_dprice;
}

double accuratePricePerUnit() {
    return _dprice;
}

Sau đó, bạn và phần còn lại trong nhóm của bạn có thể bắt tay vào quá trình chuyển đổi tất cả các máy khách của hệ thống của bạn để sử dụng phiên bản mới hơn, tốt hơn accuratePricePerUnit(). Mã máy khách sẽ chính xác hơn khi bạn đạt được tiến bộ trong nhiệm vụ đó, nhưng ngay cả những thứ cũ cũng sẽ tiếp tục hoạt động tốt như trước đây.

Dù sao đi nữa, vấn đề là đóng gói cho phép bạn thay đổi cách thức hoạt động của các bộ phận bên trong trong khi trình bày một giao diện nhất quán và điều đó giúp bạn thực hiện các thay đổi hữu ích mà không vi phạm mã khác. Nó không luôn bảo vệ bạn khỏi phải cập nhật mã khác, nhưng ít nhất nó có thể giúp bạn làm điều đó một cách có kiểm soát.


3

Theo kinh nghiệm của tôi, đóng gói làm cho việc làm "sai" trở nên khó khăn hơn nhiều. Bạn có thể nhóm các chức năng lại với nhau về mặt ngữ nghĩa và tách biệt chúng khỏi chức năng có thể dẫn đến hành vi xấu hoặc không thể đoán trước. Nó cũng có thể giúp ẩn các chi tiết từ người dùng cuối có thể giúp tăng độ an toàn và độ tin cậy.

Hãy xem xét bài đăng này của John D Cook . Hãy xem xét rằng bạn có một Breadđối tượng. Một điều tự nhiên để cắt bánh mì này. Vì vậy, bạn viết một slice()chức năng, vì vậy bạn có thể làm

slice(loaf)

với một loafđối tượng mới mà bạn đã tạo. Điều này thật ý nghĩa. Nhưng nếu bạn không cẩn thận, bạn có thể vô tình gọi

slice(finger)

với một fingerđối tượng ở đâu đó trong dự án của bạn. Điều này có thể dẫn đến những điều rất xấu. Thay vào đó, hãy đóng gói hàm / phương thức này vào một Breadlớp để bạn có thể làm điều này

loaf.slice()

Điều này chắc chắn giúp tránh finger.slice()vô tình gọi , vì fingercó lẽ không có slice()phương pháp liên quan đến nó.

Đây là một ví dụ điển hình nhưng tôi thấy nó hữu ích. Đóng gói đôi khi có thể là một khía cạnh bị đánh giá thấp của OOP, nhưng đó là một khía cạnh tốt.


2

Đóng gói giúp các nhóm lớn các nhà phát triển phối hợp công việc của họ hiệu quả hơn. Mỗi nhóm nhà phát triển hoạt động trên các mô-đun khác nhau và các mô-đun đó được gói gọn - tách mã thành một số lượng nhỏ các toán tử có sẵn rộng rãi mà việc sử dụng chúng không thể kiểm soát chặt chẽ và một số lượng lớn các toán tử nội bộ có thể kiểm soát chặt chẽ. Điều này có nghĩa là mỗi nhóm nhà phát triển có thể xác định các bất biến quan trọng đối với mô-đun của họ để duy trì và đảm bảo rằng các bất biến đó giữ bất kể nhà phát triển của các mô-đun khác làm gì.

Vì đóng gói cho phép bảo quản bất biến, nó thường được sử dụng để duy trì các bất biến an ninh / an toàn, ví dụ

  • rằng một kho dữ liệu không bao giờ được truy cập mà không có thông tin xác thực
  • tài khoản ngân hàng không bao giờ có nhiều tiền hơn số tiền đã bị xóa khỏi tài khoản khác
  • rằng các hoạt động nhất định luôn được ghi lại

Các mô hình khả năng đối tượng là một phương pháp để viết mã an ninh nhạy cảm đó là đóng gói trên steroid.

Mô hình bảo mật dựa vào việc không thể giả mạo tài liệu tham khảo; xem địa chỉ tổng hợp của các diễn viên.

Các đối tượng chỉ có thể tương tác bằng cách gửi tin nhắn trên tài liệu tham khảo. Một tài liệu tham khảo có thể được lấy bởi:

  1. điều kiện ban đầu: Ở trạng thái ban đầu của thế giới tính toán được mô tả, đối tượng A có thể đã có tham chiếu đến đối tượng B. cha mẹ: Nếu A tạo B, tại thời điểm đó A có được tham chiếu duy nhất đến B. mới được tạo.
  2. nguồn lực: Nếu A tạo B, B được sinh ra với tập hợp con các tham chiếu của A mà A đã chọn để tặng nó.
  3. giới thiệu: Nếu A có tham chiếu đến cả B và C, A có thể gửi cho B một tin nhắn có chứa tham chiếu đến C. B có thể giữ lại tham chiếu đó cho lần sử dụng tiếp theo.

Trong mô hình Khả năng đối tượng, tất cả các tính toán được thực hiện theo các quy tắc trên.

Các ưu điểm thúc đẩy lập trình hướng đối tượng, như đóng gói hoặc che giấu thông tin, mô đun hóa và phân tách mối quan tâm, tương ứng với các mục tiêu bảo mật như tách biệt đặc quyền và đặc quyền tối thiểu trong lập trình dựa trên khả năng.


2

Làm thế nào sẽ đóng gói giúp khi thực hiện các thay đổi trong mã và từ các hiệu ứng gợn sóng của nó.

Hãy để tôi cung cấp cho bạn một ví dụ điển hình và đơn giản. Đầu tiên, giả sử bạn không sử dụng đóng gói: Bạn có một bộ dữ liệu và sử dụng một mảng để lưu trữ dữ liệu đó và có một phần khác trong chương trình của bạn sử dụng mảng đó. Bây giờ, nếu tại một thời điểm nào đó, bạn quyết định rằng một danh sách được liên kết là lựa chọn tốt hơn để lưu trữ dữ liệu của bạn. Nếu bạn thay thế mảng bằng danh sách liên kết, điều gì sẽ xảy ra? Chương trình của bạn sẽ bị hỏng, trừ khi bạn thay đổi mọi nơi để thay thế logic xử lý mảng bằng logic xử lý danh sách liên kết.

Nhưng, nếu bạn sử dụng OO / Encapsulation, thì bạn có thể phân vùng chương trình của bạn thành các lớp, một lớp lưu trữ dữ liệu và khác, sử dụng dữ liệu. Trong lớp đầu tiên, bạn ẩn việc triển khai (đóng gói) và hiển thị các dịch vụ của mình thông qua các phương thức như

size()
remove(int index)
add(int index, Object o)
get(int index)

...

Trong trường hợp thứ hai này, nếu bạn thay đổi việc triển khai lớp lưu trữ từ mảng sang danh sách được liên kết hoặc sang bất kỳ thứ gì khác, nó sẽ không ảnh hưởng đến các máy khách của bạn. Không có hiệu ứng gợn.


1

Cách chính mà đóng gói giúp giảm hiệu ứng gợn sóng của thay đổi là bằng cách giữ càng nhiều chi tiết triển khai riêng tư cho lớp. Bằng cách giới hạn giao diện chỉ cho những thành viên cần sử dụng lớp, nhiều thay đổi có thể được thực hiện đối với việc triển khai mà không ảnh hưởng đến bất kỳ mã nào sử dụng lớp.

Đó dường như là điểm được tạo ra bởi văn bản bạn trích dẫn, mặc dù tôi cũng thấy nó hơi khó hiểu trong lần đọc đầu tiên.


1

Tôi nghĩ rằng nó cho phép bạn thay đổi chức năng của lớp mà không cần, mặc dù không phải lúc nào cũng giới thiệu các ngắt BC (Tương thích nhị phân hoặc hành vi). Đó là, bạn có thể thay đổi cách lớp của bạn thực hiện 'một cái gì đó' mà không phải thay đổi cách người dùng cuối bảo nó làm 'cái gì đó'.

Ví dụ bạn đã đưa ra về việc thay đổi kiểu trả về là dấu ngắt BC, bởi vì bất kỳ ai trước đây đã sử dụng lớp của bạn sẽ không thể sử dụng phiên bản mới mà không biên dịch lại. Đây là điều chỉ nên được thực hiện như là phương sách cuối cùng và trong một môi trường chuyên nghiệp chỉ có thể được thực hiện với sự giải phóng mặt bằng từ các kiến ​​trúc sư và sau khi thủ tục giấy tờ được nộp, khách hàng đã thông báo, v.v.

Nó cũng cung cấp cho bạn toàn quyền kiểm soát trạng thái của đối tượng của bạ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.