Làm thế nào để một biến giới thiệu nhà nước?


11

Tôi đã đọc "Tiêu chuẩn mã hóa C ++" và dòng này đã có:

Các biến giới thiệu trạng thái, và bạn nên xử lý càng ít trạng thái càng tốt, với thời gian sống càng ngắn càng tốt.

Không có bất cứ điều gì đột biến cuối cùng thao túng nhà nước? Bạn nên làm gì với trạng thái càng ít càng tốt ?

Trong một ngôn ngữ không tinh khiết như C ++, không phải quản lý nhà nước thực sự là những gì bạn đang làm sao? Và những cách khác để đối phó với trạng thái càng ít càng tốt ngoài việc hạn chế tuổi thọ biến?

Câu trả lời:


16

Không có bất kỳ điều gì có thể thay đổi thực sự thao túng nhà nước?

Đúng.

Và "bạn nên đối phó với trạng thái nhỏ" nghĩa là gì?

Nó có nghĩa là trạng thái ít hơn là tốt hơn trạng thái nhiều hơn. Nhiều nhà nước có xu hướng giới thiệu phức tạp hơn.

Trong một ngôn ngữ không tinh khiết như C ++, không phải quản lý nhà nước thực sự là những gì bạn đang làm sao?

Đúng.

Những cách khác để "đối phó với trạng thái nhỏ" ngoài việc giới hạn thời gian sống thay đổi là gì?

Giảm thiểu số lượng biến. Mã cô lập thao tác một số trạng thái thành một đơn vị độc lập để các phần mã khác có thể bỏ qua nó.


9

Không có bất kỳ điều gì có thể thay đổi thực sự thao túng nhà nước?

Đúng. Trong C ++, những thứ duy nhất có thể thay đổi là các constbiến (không ).

Và "bạn nên đối phó với trạng thái nhỏ" nghĩa là gì?

Chương trình càng ít trạng thái, càng dễ hiểu những gì nó làm. Vì vậy, bạn không nên giới thiệu trạng thái không cần thiết và bạn không nên giữ nó một khi bạn không còn cần nó nữa.

Trong một ngôn ngữ không tinh khiết như C ++, không phải quản lý nhà nước thực sự là những gì bạn đang làm sao?

Trong một ngôn ngữ đa mô hình như C ++, thường có một sự lựa chọn giữa một phương pháp "thuần túy" hoặc một cách tiếp cận dựa trên trạng thái, hoặc một loại lai nào đó. Trong lịch sử, hỗ trợ ngôn ngữ cho lập trình chức năng khá yếu so với một số ngôn ngữ, nhưng nó đang được cải thiện.

Những cách khác để "đối phó với trạng thái nhỏ" ngoài việc giới hạn thời gian sống thay đổi là gì?

Hạn chế phạm vi cũng như thời gian tồn tại, để giảm sự ghép nối giữa các đối tượng; ủng hộ các biến cục bộ hơn là các biến toàn cục và riêng tư hơn là các thành viên đối tượng công cộng.


5

trạng thái có nghĩa là một cái gì đó đang được lưu trữ ở đâu đó để bạn có thể tham khảo nó sau này.

Tạo một biến, tạo một số không gian để bạn lưu trữ một số dữ liệu. Dữ liệu này là trạng thái của chương trình của bạn.

Bạn sử dụng nó để làm mọi thứ với, thay đổi nó, tính toán với nó, v.v.

Đây là trạng thái , trong khi những điều bạn không làm .

Trong một ngôn ngữ chức năng, bạn chủ yếu chỉ xử lý các chức năng và chuyển các chức năng xung quanh giống như chúng là các đối tượng. Mặc dù các hàm này không có trạng thái và truyền hàm xung quanh, nhưng không có trạng thái nào (ngoài khả năng bên trong hàm).

Trong C ++, bạn có thể tạo các đối tượng hàm , structhoặc classcác kiểu đã operator()()quá tải. Các đối tượng hàm này có thể có trạng thái cục bộ, mặc dù điều này không nhất thiết phải được chia sẻ giữa các mã khác trong chương trình của bạn. Functor (tức là các đối tượng chức năng) rất dễ dàng để vượt qua. Đây là khoảng cách gần như bạn có thể bắt chước một mô hình chức năng trong C ++. (AFAIK)

Có ít hoặc không có trạng thái có nghĩa là bạn có thể dễ dàng tối ưu hóa chương trình của mình để thực thi song song, vì không có gì có thể chia sẻ giữa các luồng hoặc CPU, vì vậy không có gì có thể tạo ra sự tranh chấp và không có gì bạn phải bảo vệ trước các cuộc đua dữ liệu, v.v.


2

Những người khác đã cung cấp câu trả lời tốt cho 3 câu hỏi đầu tiên.

Và những cách khác để "đối phó với trạng thái càng ít càng tốt" ngoài việc giới hạn tuổi thọ biến đổi là gì?

Câu trả lời chính cho câu hỏi số 1 là có, bất cứ điều gì đột biến cuối cùng đều tác động đến trạng thái. Chìa khóa sau đó là không đột biến mọi thứ. Các loại không thay đổi, sử dụng kiểu lập trình chức năng trong đó kết quả của một hàm được truyền trực tiếp sang hàm kia và không được lưu trữ, truyền tin nhắn hoặc sự kiện trực tiếp thay vì lưu trữ trạng thái, tính toán giá trị thay vì lưu trữ và cập nhật chúng ...

Nếu không, bạn sẽ bị hạn chế tác động của nhà nước; hoặc thông qua tầm nhìn hoặc suốt đời.


1

Và "bạn nên đối phó với trạng thái nhỏ" nghĩa là gì?

Điều này có nghĩa là các lớp học của bạn nên càng nhỏ càng tốt, đại diện tối ưu cho một sự trừu tượng hóa duy nhất. Nếu bạn đặt 10 biến trong lớp, rất có thể bạn đang làm sai điều gì đó và nên xem cách cấu trúc lại lớp của bạn.


1

Để hiểu cách thức một chương trình hoạt động, bạn phải hiểu những thay đổi trạng thái của nó. Bạn càng có ít trạng thái và càng nhiều địa phương đối với mã sử dụng nó, điều này sẽ càng dễ dàng hơn.

Nếu bạn đã từng làm việc với một chương trình có số lượng lớn các biến toàn cục, bạn sẽ hiểu ngầm.


1

Nhà nước chỉ đơn giản là lưu trữ dữ liệu. Mỗi biến thực sự là một loại trạng thái, nhưng chúng ta thường sử dụng "trạng thái" để chỉ dữ liệu tồn tại giữa các hoạt động. Như một ví dụ đơn giản, vô nghĩa, bạn có thể có một lớp lưu trữ bên trong một intvà có increment()và các decrement()hàm thành viên. Ở đây, giá trị bên trong là trạng thái vì nó tồn tại trong vòng đời của thể hiện của lớp này. Nói cách khác, giá trị là trạng thái của đối tượng.

Lý tưởng nhất là trạng thái mà một lớp định nghĩa phải càng nhỏ càng tốt với mức dự phòng tối thiểu. Điều này giúp lớp của bạn đáp ứng nguyên tắc trách nhiệm duy nhất , cải thiện việc đóng gói và giảm độ phức tạp. Trạng thái của một đối tượng nên được đóng gói hoàn toàn bởi giao diện cho đối tượng đó. Điều này có nghĩa là kết quả của bất kỳ hoạt động nào trên đối tượng đó sẽ được dự đoán dựa trên ngữ nghĩa của đối tượng. Bạn có thể cải thiện hơn nữa việc đóng gói bằng cách giảm thiểu số lượng chức năng có quyền truy cập vào trạng thái .

Đây là một trong những lý do chính để tránh nhà nước toàn cầu. Trạng thái toàn cầu có thể giới thiệu một phụ thuộc cho một đối tượng mà không có giao diện thể hiện nó, làm cho trạng thái này bị ẩn khỏi người dùng của đối tượng. Gọi một hoạt động trên một đối tượng có sự phụ thuộc toàn cầu có thể có kết quả khác nhau và không thể đoán trước.


1

Không có bất cứ điều gì đột biến cuối cùng thao túng nhà nước?

Đúng, nhưng nếu nó đứng sau một hàm thành viên của một lớp nhỏ là thực thể duy nhất trong toàn bộ hệ thống có thể thao túng trạng thái riêng tư của nó, thì trạng thái đó có phạm vi rất hẹp.

Bạn nên làm gì với trạng thái càng ít càng tốt?

Từ quan điểm của biến: càng ít dòng mã có thể truy cập nó càng tốt. Thu hẹp phạm vi của biến đến mức tối thiểu.

Từ quan điểm của dòng mã: càng ít biến số có thể truy cập được từ dòng mã đó càng tốt. Thu hẹp số lượng biến mà dòng mã có thể truy cập (thậm chí không quan trọng đến mức nó truy cập được hay không, tất cả vấn đề là liệu nó có thể hay không ).

Biến toàn cầu là rất xấu bởi vì chúng có phạm vi tối đa. Ngay cả khi họ được truy cập từ 2 dòng mã trong một cơ sở mã, từ dòng POV của mã, một biến toàn cục luôn có thể truy cập được. Từ POV của biến, một biến toàn cục có liên kết ngoài có thể truy cập được đối với mọi dòng mã trong toàn bộ cơ sở mã (hoặc mọi dòng mã bao gồm tiêu đề nào). Mặc dù chỉ được truy cập thực sự bởi 2 dòng mã, nếu biến toàn cục hiển thị với 400.000 dòng mã, danh sách nghi phạm ngay lập tức của bạn khi bạn thấy nó được đặt thành trạng thái không hợp lệ thì sẽ có 400.000 mục nhập (có thể nhanh chóng giảm xuống 2 mục có công cụ, tuy nhiên, danh sách trước mắt sẽ có 400.000 nghi phạm và đó không phải là điểm khởi đầu đáng khích lệ).

Tương tự như vậy, ngay cả khi một biến toàn cục bắt đầu chỉ được sửa đổi bởi 2 dòng mã trong toàn bộ cơ sở mã, xu hướng đáng tiếc của các cơ sở mã hóa sẽ phát triển ngược lại sẽ có xu hướng tăng số lượng đó, đơn giản vì nó có thể tăng lên nhiều các nhà phát triển, điên cuồng đáp ứng thời hạn, xem biến toàn cầu này và nhận ra họ có thể dùng các phím tắt thông qua nó.

Trong một ngôn ngữ không tinh khiết như C ++, không phải quản lý nhà nước thực sự là những gì bạn đang làm sao?

Phần lớn, vâng, trừ khi bạn sử dụng C ++ theo cách rất kỳ lạ, bạn phải xử lý các cấu trúc dữ liệu bất biến tùy chỉnh và lập trình chức năng thuần túy - đó cũng thường là nguồn gốc của hầu hết các lỗi khi quản lý nhà nước trở nên phức tạp và phức tạp là thường là một chức năng của khả năng hiển thị / tiếp xúc của trạng thái đó.

Và những cách khác để đối phó với trạng thái càng ít càng tốt ngoài việc hạn chế tuổi thọ biến?

Tất cả những điều này nằm trong phạm vi giới hạn phạm vi của một biến, nhưng có nhiều cách để làm điều này:

  • Tránh các biến toàn cầu thô như bệnh dịch hạch. Ngay cả một số hàm setter / getter toàn cầu câm làm thu hẹp khả năng hiển thị của biến đó và ít nhất cho phép một số cách duy trì bất biến (ví dụ: nếu biến toàn cục không bao giờ được phép là giá trị âm, thì setter có thể duy trì bất biến đó). Tất nhiên, ngay cả một thiết kế setter / getter trên đầu của biến toàn cục là thiết kế khá kém, quan điểm của tôi là nó vẫn tốt hơn.
  • Làm cho lớp học của bạn nhỏ hơn khi có thể. Một lớp có hàng trăm hàm thành viên, 20 biến thành viên và 30.000 dòng mã thực hiện nó sẽ có các biến riêng tư "toàn cầu", vì tất cả các biến đó sẽ có thể truy cập được vào các hàm thành viên bao gồm 30k dòng mã. Bạn có thể nói "độ phức tạp trạng thái" trong trường hợp đó, trong khi chiết khấu các biến cục bộ trong mỗi hàm thành viên, là 30,000*20=600,000. Nếu có 10 biến toàn cục có thể truy cập trên đó, thì độ phức tạp trạng thái có thể là như thế 30,000*(20+10)=900,000. Một "độ phức tạp trạng thái" lành mạnh (loại số liệu được phát minh cá nhân của tôi) nên có trong hàng ngàn hoặc thấp hơn cho các lớp, không phải hàng chục nghìn và chắc chắn không phải hàng trăm nghìn. Đối với các chức năng miễn phí, hãy nói hàng trăm hoặc thấp hơn trước khi chúng tôi bắt đầu bị đau đầu nghiêm trọng trong bảo trì.
  • Cũng giống như trên, không thực hiện một cái gì đó như một chức năng thành viên hoặc chức năng bạn bè mà có thể không phải là tháng mười một, không kết bạn chỉ sử dụng giao diện chung của lớp. Các hàm như vậy không thể truy cập các biến riêng của lớp và do đó giảm khả năng xảy ra lỗi bằng cách giảm phạm vi của các biến riêng đó.
  • Tránh khai báo các biến từ lâu trước khi chúng thực sự cần thiết trong một hàm (nghĩa là tránh kiểu C kế thừa, khai báo tất cả các biến ở đầu hàm ngay cả khi chúng chỉ cần nhiều dòng bên dưới). Nếu bạn vẫn sử dụng phong cách này, ít nhất là phấn đấu cho các chức năng ngắn hơn.

Beyond Variabled: Tác dụng phụ

Rất nhiều hướng dẫn tôi liệt kê ở trên đang giải quyết quyền truy cập trực tiếp vào trạng thái thô, có thể thay đổi (biến). Tuy nhiên, trong một cơ sở mã đủ phức tạp, chỉ cần thu hẹp phạm vi của các biến thô sẽ không đủ để dễ dàng suy luận về tính chính xác.

Bạn có thể có một cấu trúc dữ liệu trung tâm, đằng sau một giao diện trừu tượng hoàn toàn RẮN, hoàn toàn có khả năng duy trì hoàn hảo các bất biến, và cuối cùng vẫn gặp rất nhiều đau buồn do sự phơi bày rộng rãi của trạng thái trung tâm này. Một ví dụ về trạng thái trung tâm không nhất thiết phải truy cập toàn cầu mà chỉ có thể truy cập rộng rãi là biểu đồ cảnh trung tâm của công cụ trò chơi hoặc cấu trúc dữ liệu lớp trung tâm của Photoshop.

Trong những trường hợp như vậy, ý tưởng về "trạng thái" vượt ra ngoài các biến thô và chỉ đến các cấu trúc dữ liệu và những thứ thuộc loại đó. Nó cũng giúp giảm phạm vi của chúng (giảm số lượng dòng có thể gọi các hàm gián tiếp biến đổi chúng).

nhập mô tả hình ảnh ở đây

Lưu ý cách tôi cố tình đánh dấu ngay cả giao diện là màu đỏ ở đây, vì từ cấp độ kiến ​​trúc rộng, thu nhỏ, truy cập vào giao diện đó vẫn đang thay đổi trạng thái, mặc dù gián tiếp. Lớp có thể duy trì bất biến như là kết quả của giao diện, nhưng điều đó chỉ đi xa về khả năng suy luận về tính chính xác của chúng tôi.

Trong trường hợp này, cấu trúc dữ liệu trung tâm nằm phía sau một giao diện trừu tượng thậm chí có thể không truy cập được trên toàn cầu. Nó chỉ có thể được tiêm và sau đó được gián tiếp đột biến (thông qua các hàm thành viên) từ một khối các hàm trong cơ sở mã phức tạp của bạn.

Trong trường hợp như vậy, ngay cả khi cấu trúc dữ liệu duy trì hoàn hảo các bất biến của riêng nó, những điều kỳ lạ có thể xảy ra ở cấp độ rộng hơn (ví dụ: trình phát âm thanh có thể duy trì tất cả các loại bất biến như mức âm lượng không bao giờ vượt quá phạm vi 0% đến 100%, nhưng điều đó không bảo vệ nó khỏi người dùng nhấn nút phát và có một đoạn âm thanh ngẫu nhiên khác với đoạn mà anh ta tải gần đây nhất bắt đầu phát khi một sự kiện được kích hoạt khiến danh sách phát được chia sẻ lại theo cách hợp lệ nhưng vẫn không mong muốn, hành vi rối rắm từ góc độ người dùng rộng).

Cách để tự bảo vệ mình trong các tình huống phức tạp này là "thắt cổ chai" các vị trí trong cơ sở mã có thể gọi các chức năng gây ra tác dụng phụ bên ngoài ngay cả từ cách nhìn rộng hơn của hệ thống vượt ra ngoài trạng thái thô và ngoài giao diện.

nhập mô tả hình ảnh ở đây

Trông kỳ lạ như thế này, bạn có thể thấy rằng không có "trạng thái" nào (hiển thị màu đỏ và điều này không có nghĩa là "biến thô", nó chỉ có nghĩa là một "đối tượng" và thậm chí có thể đằng sau một giao diện trừu tượng) đang được truy cập bởi nhiều nơi . Mỗi chức năng đều có quyền truy cập vào trạng thái cục bộ mà trình cập nhật trung tâm cũng có thể truy cập và trạng thái trung tâm chỉ có thể truy cập vào trình cập nhật trung tâm (làm cho nó không còn là trung tâm mà là bản chất cục bộ).

Điều này chỉ dành cho các cơ sở mã thực sự phức tạp, giống như một trò chơi kéo dài 10 triệu dòng mã, nhưng nó có thể giúp rất nhiều trong việc suy luận về tính chính xác của phần mềm của bạn và thấy rằng các thay đổi của bạn mang lại kết quả có thể dự đoán được, khi bạn giới hạn / tắc nghẽn đáng kể số lượng của những nơi có thể đột biến các trạng thái quan trọng mà toàn bộ kiến ​​trúc xoay quanh để hoạt động chính xác.

Ngoài các biến thô là tác dụng phụ bên ngoài và tác dụng phụ bên ngoài là nguồn gây ra lỗi ngay cả khi chúng bị giới hạn trong một số ít chức năng thành viên. Nếu một nhóm chức năng có thể gọi trực tiếp các nhóm chức năng đó, thì có một nhóm chức năng trong hệ thống có thể gián tiếp gây ra tác dụng phụ bên ngoài và điều đó làm tăng sự phức tạp. Nếu chỉ có một nơi trong cơ sở mã có quyền truy cập vào các chức năng thành viên đó và một con đường thực thi đó không được kích hoạt bởi các sự kiện lẻ tẻ ở khắp mọi nơi, mà thay vào đó được thực hiện theo kiểu rất dễ kiểm soát, có thể dự đoán được, thì nó sẽ giảm độ phức tạp.

Phức tạp nhà nước

Ngay cả sự phức tạp của nhà nước là một yếu tố khá quan trọng cần tính đến. Một cấu trúc đơn giản, có thể truy cập rộng rãi đằng sau một giao diện trừu tượng, không quá khó để gây rối.

Một cấu trúc dữ liệu đồ thị phức tạp đại diện cho biểu diễn logic cốt lõi của một kiến ​​trúc phức tạp khá dễ gây rối và theo cách thậm chí không vi phạm các bất biến của đồ thị. Một biểu đồ phức tạp hơn nhiều lần so với một cấu trúc đơn giản và do đó, nó trở nên quan trọng hơn trong trường hợp như vậy để giảm độ phức tạp nhận thức của cơ sở mã để giảm số lượng vị trí có quyền truy cập vào cấu trúc biểu đồ đó đến mức tối thiểu tuyệt đối, và trong đó loại chiến lược "cập nhật trung tâm" chuyển sang mô hình kéo để tránh lẻ tẻ, việc đẩy trực tiếp vào cấu trúc dữ liệu đồ thị từ khắp nơi có thể thực sự được đền đáp.

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.