it-swarm-vi.com

Có một điều như là có quá nhiều chức năng / phương thức riêng tư?

Tôi hiểu tầm quan trọng của mã tài liệu tốt. Nhưng tôi cũng hiểu tầm quan trọng của tự viết tài liệu . Càng dễ đọc trực quan một chức năng cụ thể, chúng ta càng có thể di chuyển nhanh hơn trong quá trình bảo trì phần mềm.

Như đã nói, tôi thích tách các hàm lớn thành các hàm nhỏ hơn khác. Nhưng tôi làm như vậy đến mức một lớp có thể có tới năm trong số chúng chỉ để phục vụ một phương thức công khai. Bây giờ nhân năm phương thức riêng tư với năm phương thức công khai và bạn có khoảng hai mươi lăm phương thức ẩn có thể sẽ chỉ được gọi một lần bởi những phương thức công khai đó.

Chắc chắn, giờ đây việc đọc các phương thức công khai đó trở nên dễ dàng hơn, nhưng tôi không thể không nghĩ rằng có quá nhiều chức năng là thực tiễn tồi.

[Chỉnh sửa]

Mọi người đã hỏi tôi tại sao tôi nghĩ rằng có quá nhiều chức năng là thực hành tồi.

Câu trả lời đơn giản: đó là một cảm giác ruột.

Tôi tin rằng, không một chút nào, được hỗ trợ bởi bất kỳ giờ kinh nghiệm kỹ thuật phần mềm nào. Đó chỉ là một sự không chắc chắn đã cho tôi một "khối nhà văn", nhưng đối với một lập trình viên.

Trước đây, tôi chỉ lập trình các dự án cá nhân. Gần đây tôi đã chuyển sang các dự án dựa trên nhóm. Bây giờ, tôi muốn đảm bảo rằng những người khác có thể đọc và hiểu mã của tôi.

Tôi không chắc những gì sẽ cải thiện mức độ dễ đọc. Một mặt, tôi đã nghĩ đến việc tách một chức năng lớn thành các chức năng nhỏ khác với các tên dễ hiểu. Nhưng có một mặt khác của tôi nói rằng nó chỉ là dư thừa.

Vì vậy, tôi đang yêu cầu điều này soi sáng bản thân để chọn đúng con đường.

[Chỉnh sửa]

Bên dưới, tôi đã bao gồm hai phiên bản về cách tôi có thể giải quyết vấn đề của mình. Người đầu tiên giải quyết nó bằng cách không tách các đoạn mã lớn. Cái thứ hai không tách rời .

Phiên bản đầu tiên:

public static int Main()
{
    // Displays the menu.
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

Phiên bản thứ hai:

public static int Main()
{
    DisplayMenu();
}

private static void DisplayMenu()
{
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

Trong các ví dụ trên, hàm sau gọi một hàm sẽ chỉ được sử dụng một lần trong toàn bộ thời gian chạy của chương trình.

Lưu ý: mã ở trên được khái quát hóa, nhưng nó có cùng bản chất với vấn đề của tôi.

Bây giờ, đây là câu hỏi của tôi: cái nào? Tôi chọn cái thứ nhất hay cái thứ hai?

63
Sal

Bây giờ nhân năm phương thức riêng tư với năm phương thức công khai và bạn có khoảng hai mươi lăm phương thức ẩn có thể sẽ chỉ được gọi một lần bởi những phương thức công khai đó.

Đây là cái được gọi là Encapsulation , tạo ra Trừu tượng hóa kiểm soát ở cấp độ cao hơn. Đây là một điều tốt.

Điều này có nghĩa là bất kỳ ai đọc mã của bạn, khi họ đến phương thức startTheEngine() trong mã của bạn, có thể bỏ qua tất cả các chi tiết cấp thấp hơn như openIgnitionModule(), turnDistributorMotor() , sendSparksToSparkPlugs(), injectFuelIntoCylinders(), activateStarterSolenoid(), và tất cả các hàm phức tạp, nhỏ, khác phải được chạy để tạo điều kiện cho hàm lớn hơn, trừu tượng hơn nhiều của startTheEngine().

Trừ khi vấn đề bạn đang giải quyết trong mã của bạn liên quan trực tiếp đến một trong những thành phần đó, những người duy trì mã có thể tiếp tục, bỏ qua chức năng đóng gói, đóng hộp cát.

Điều này cũng có thêm lợi thế của làm cho mã của bạn dễ kiểm tra hơn. . Chẳng hạn, tôi có thể viết một trường hợp thử nghiệm cho turnAlternatorMotor(int revolutionRate) và kiểm tra chức năng của nó hoàn toàn độc lập với các hệ thống khác. Nếu có vấn đề với chức năng đó và đầu ra không như tôi mong đợi, thì tôi biết vấn đề là gì.

Mã không được chia thành các thành phần khó kiểm tra hơn nhiều. Đột nhiên, những người bảo trì của bạn chỉ nhìn vào sự trừu tượng thay vì có thể đào sâu vào các thành phần có thể đo lường được.

Lời khuyên của tôi là hãy tiếp tục làm những gì bạn đang làm vì mã của bạn sẽ mở rộng, dễ bảo trì và có thể được sử dụng và cập nhật trong nhiều năm tới.

36
jmort253

Có và không. Nguyên lý cơ bản là: một phương pháp nên làm một việc và chỉ một việc

Thật đúng khi "chia nhỏ" phương thức của bạn thành các phương thức nhỏ hơn. Sau đó, một lần nữa, các phương thức đó tối ưu đủ chung để không chỉ phục vụ phương thức "lớn" đó nhưng có thể được sử dụng lại ở những nơi khác. Trong một số trường hợp, một phương thức sẽ tuân theo một cấu trúc cây đơn giản, như Phương thức khởi tạo gọi là LaunchizePlugins, InitializeInterface, v.v.

Nếu bạn có một phương thức/lớp thực sự lớn thì đó thường là một dấu hiệu cho thấy nó đang hoạt động rất nhiều và bạn cần thực hiện một số phép tái cấu trúc để phá vỡ "blob". Perphaps ẩn một số phức tạp trong một lớp khác dưới một sự trừu tượng hóa, và sử dụng tiêm phụ thuộc

22
Homde

Tôi nghĩ nói chung tốt hơn là sai ở bên cạnh quá nhiều chức năng chứ không phải quá ít. Hai trường hợp ngoại lệ cho quy tắc mà tôi đã thấy trong thực tế là dành cho KHÔ YAGNI = nguyên tắc. Nếu bạn có nhiều chức năng gần như giống hệt nhau, bạn nên kết hợp chúng và sử dụng các tham số để tránh lặp lại chính mình. Bạn cũng có thể có quá nhiều chức năng nếu bạn tạo chúng "chỉ trong trường hợp" và chúng không được sử dụng. Tôi thấy hoàn toàn không có gì sai khi có một chức năng chỉ được sử dụng một lần nếu nó thêm khả năng đọc và bảo trì.

17
Karl Bielefeldt

câu trả lời tuyệt vời của jmort253 đã truyền cảm hứng cho tôi theo dõi câu trả lời "có, nhưng".

Có nhiều phương pháp riêng tư nhỏ không phải là một điều xấu, nhưng hãy chú ý đến cảm giác khó chịu đó khiến bạn phải đặt câu hỏi ở đây :). Nếu bạn đến một điểm mà bạn đang viết các bài kiểm tra chỉ tập trung vào các phương thức riêng tư (bằng cách gọi trực tiếp hoặc bằng cách thiết lập một kịch bản sao cho một kịch bản được gọi theo một cách nhất định để bạn có thể kiểm tra kết quả) thì bạn có thể kiểm tra kết quả) bạn nên lùi lại một bước.

Những gì bạn có thể có là một lớp mới với giao diện công cộng tập trung hơn đang cố gắng thoát ra. Tại thời điểm đó, bạn có thể muốn nghĩ về việc trích xuất một lớp ra để gói gọn một phần chức năng lớp hiện có của bạn hiện đang sống theo phương thức riêng tư. Bây giờ lớp ban đầu của bạn có thể sử dụng lớp mới của bạn làm phụ thuộc và bạn có thể viết các bài kiểm tra tập trung hơn vào lớp đó trực tiếp.

10
Pete Hodgson

Hầu như mọi dự án OO tôi từng tham gia đều chịu thiệt hại nặng nề từ các lớp quá lớn và các phương thức quá dài.

Khi tôi cảm thấy cần một bình luận giải thích phần tiếp theo của mã, sau đó tôi trích xuất phần đó thành một phương thức riêng biệt. Về lâu dài, điều này làm cho mã ngắn hơn. Những phương pháp nhỏ đó được sử dụng lại nhiều hơn bạn mong đợi ban đầu. Bạn bắt đầu nhìn thấy cơ hội để thu thập một loạt chúng vào một lớp riêng biệt. Chẳng mấy chốc bạn đang nghĩ về vấn đề của mình ở cấp độ cao hơn, và toàn bộ nỗ lực diễn ra nhanh hơn nhiều. Các tính năng mới dễ viết hơn, bởi vì bạn có thể xây dựng trên các lớp nhỏ mà bạn đã tạo từ các phương thức nhỏ đó.

8
kevin cline

Một lớp học với 5 phương thức công khai và 25 phương thức riêng tư dường như không lớn đối với tôi. Chỉ cần đảm bảo rằng các lớp của bạn có trách nhiệm được xác định rõ và đừng quá lo lắng về số lượng phương thức.

Điều đó nói rằng, các phương thức riêng đó nên tập trung vào một khía cạnh cụ thể của toàn bộ tác vụ, nhưng không phải theo cách thức "doS SomethingPart1", "doS SomethingPart2". Bạn chẳng đạt được gì nếu những phương thức riêng tư đó chỉ là những phần của một câu chuyện dài được phân chia tùy tiện, mỗi câu chuyện đều vô nghĩa bên ngoài toàn bộ bối cảnh.

7
user281377

Trích từ R. Martin's Mã sạch (trang 176):

Ngay cả các khái niệm cơ bản như loại bỏ trùng lặp, biểu cảm mã và SRP có thể được đưa quá xa. Trong nỗ lực làm cho các lớp và phương thức của chúng ta nhỏ đi, chúng ta có thể tạo ra quá nhiều lớp và phương thức nhỏ. Vì vậy, quy tắc này [tối thiểu hóa số lượng các lớp và phương thức] cho thấy rằng chúng ta cũng giữ cho hàm và số lớp của chúng ta ở mức thấp. Số lượng cao và phương pháp đôi khi là kết quả của chủ nghĩa giáo điều vô nghĩa.

4
user2418306

Một số tùy chọn:

  1. Tốt rồi. Chỉ cần đặt tên cho các phương thức riêng tư cũng như bạn đặt tên cho các phương thức công khai của bạn. Và đặt tên cho phương pháp công khai của bạn tốt.

  2. Tóm tắt một số phương thức của trình trợ giúp này thành các lớp trình trợ giúp hoặc các mô đun trình trợ giúp. Và chắc chắn rằng các lớp/mô-đun trợ giúp này được đặt tên tốt và là bản tóm tắt vững chắc trong chính chúng.

3
yfeldblum

Tôi không nghĩ đã từng có vấn đề về "quá nhiều phương thức riêng tư" nếu cảm thấy như vậy có lẽ đó là một triệu chứng của kiến ​​trúc mã kém.

Đây là cách tôi nghĩ về nó ... Nếu kiến ​​trúc được thiết kế tốt, nhìn chung thì rõ ràng mã X nên ở đâu. Có thể chấp nhận được nếu có một vài trường hợp ngoại lệ cho vấn đề này - nhưng chúng cần phải thực sự đặc biệt nếu không cấu trúc lại kiến ​​trúc để xử lý chúng theo tiêu chuẩn.

Nếu vấn đề là khi mở lớp của bạn, nó chứa đầy các phương thức riêng tư đang chia các phần lớn hơn thành các đoạn mã nhỏ hơn, thì có lẽ đây là một triệu chứng của kiến ​​trúc bị thiếu. Thay vì các lớp và kiến ​​trúc, vùng mã này đã được triển khai theo cách thủ tục trong một lớp.

Tìm sự cân bằng ở đây phụ thuộc vào dự án và các yêu cầu của nó. Đối số cho điều này là câu nói rằng một lập trình viên cơ sở có thể loại bỏ giải pháp trong 50 dòng mã cần một kiến ​​trúc sư 50 lớp.

1
Michael Shaw

Có một điều như là có quá nhiều chức năng/phương thức riêng tư?

Đúng.

Trong Python khái niệm "private" (được sử dụng bởi C++, Java và C #) không thực sự tồn tại.

Có một quy ước đặt tên "riêng tư", nhưng đó là nó.

Riêng tư có thể dẫn đến mã khó kiểm tra. Nó cũng có thể phá vỡ "Nguyên tắc đóng mở" bằng cách đóng mã đơn giản.

Do đó, đối với những người đã sử dụng Python, các hàm riêng không có giá trị. Chỉ cần làm cho mọi thứ công khai và được thực hiện với nó.

0
S.Lott