Tại sao tốt để chia một chương trình thành nhiều lớp? [đóng cửa]


62

Tôi vẫn còn là học sinh cấp ba (đang học lớp 10) và tôi chưa tham gia khóa học máy tính thực tế ở trường. Tất cả mọi thứ tôi đã làm cho đến nay là thông qua sách. Những cuốn sách đó đã dạy tôi các khái niệm như kế thừa, nhưng làm thế nào để chia một chương trình thành nhiều lớp giúp ích? Những cuốn sách không bao giờ nói với tôi.

Tôi đang hỏi điều này chủ yếu vì một dự án gần đây. Đây là một trò chơi video arcade, giống như một trò chơi Flash như một số người đã nói (mặc dù tôi không biết trò chơi Flash là gì). Vấn đề là, nó chỉ có một lớp. Nó hoạt động hoàn toàn tốt (tuy nhiên một chút chậm trễ) chỉ với một lớp. Vì vậy, tôi chỉ hỏi làm thế nào để chia nó thành nhiều lớp sẽ giúp nó.

Dự án này là ở Java và tôi là người duy nhất làm việc với nó, cho hồ sơ.


1
Để làm cho mỗi phần mềm đơn giản hơn! infoq.com/presentations/Simple-Made- Easy
TehShrike

49
Khi bạn đọc sách của mình, chúng có được chia thành các chương và phần không? Chúng tôi chia một chương trình thành các lớp để sắp xếp mọi thứ, giống như sách chia văn bản thành các chương để sắp xếp mọi thứ.
riwalk

12
Người La Mã thường nói: chia et đế chế.
Giorgio

7
@Giorgio: hoặc bằng tiếng Anh, vì tiếng Latin không còn được sử dụng nữa: Divide And Conquer .
Matthieu M.

40
Xem xét bạn đang học lớp 10, và đã có thể tạo thành một câu hỏi thông minh, cung cấp tất cả các chi tiết cần thiết cho câu trả lời hay, cung cấp ngữ cảnh và kinh nghiệm tương đối của bạn, cũng như thông tin cơ bản về lý do bạn hỏi câu hỏi; bạn đã có trình độ cao hơn nhiều người tôi hiện đang làm việc với ...
CaffGeek

Câu trả lời:


71

Câu trả lời đơn giản nhất là nếu bạn đặt mọi thứ vào một lớp, bạn phải lo lắng về mọi thứ ngay lập tức khi bạn viết mã mới. Điều này có thể hoạt động cho các dự án nhỏ, nhưng đối với các ứng dụng lớn (chúng ta đang nói hàng trăm ngàn dòng), điều này nhanh chóng trở thành không thể.

Để giải quyết vấn đề này, bạn chia các phần chức năng thành các lớp riêng của chúng và gói gọn tất cả logic. Sau đó, khi bạn muốn làm việc trên lớp, bạn không cần phải suy nghĩ về những gì khác đang diễn ra trong mã. Bạn chỉ có thể tập trung vào đoạn mã nhỏ đó. Điều này là vô giá để làm việc hiệu quả, tuy nhiên thật khó để đánh giá cao nếu không làm việc trên các ứng dụng rất lớn.

Tất nhiên, có vô số lợi ích khác khi chia mã của bạn thành các phần nhỏ hơn: mã dễ bảo trì hơn, dễ kiểm tra hơn, dễ sử dụng hơn, v.v., nhưng đối với tôi, lợi ích lớn nhất là nó giúp các chương trình lớn có thể quản lý được bằng cách giảm số lượng mã bạn cần phải suy nghĩ về một lúc


7
Rất nhiều khái niệm / ý tưởng trong lập trình (nguyên tắc OO, kiểm soát nguồn phân tán, tiêu chuẩn mã hóa) chỉ thực sự có ý nghĩa khi bạn làm việc trên các dự án tương đối lớn trong một nhóm. Bạn sẽ hiểu tại sao khi bạn thực sự làm việc trên các dự án như vậy.
joshin4colours

40
Điều đáng chú ý việc chia dự án thành nhiều lớp / tệp không giúp ích nhiều. Điều thực sự quan trọng là có các lớp độc lập, vì vậy việc thay đổi một lớp không đòi hỏi phải biết bất cứ điều gì khác về chương trình (và sử dụng lớp không yêu cầu bất kỳ kiến ​​thức nào về cách thức triển khai). Tôi đưa nó lên bởi vì tôi thường xuyên thấy mã với rất nhiều lớp, nhưng không có sự đóng gói thực sự. Đóng gói là phần quan trọng - làm thế nào bạn đạt được nó chỉ là chi tiết.
Phục hồi Monica

2
Một số từ chính sẽ là "ghép" hoặc "tách", "đóng gói", "ẩn thông tin".
marktani

@BrendanLong, tôi đồng ý và tôi cũng sẽ thêm rằng đóng gói là gần như không thể. Trừ khi bạn đang viết các chương trình riêng biệt tất nhiên ... NHƯNG thường có nhiều phần không phụ thuộc vào nhau, nhưng chỉ có phần phụ thuộc chung
Jo So

29

Chà, câu trả lời đơn giản nhất có thể là "Nó giúp tổ chức mọi thứ." Nếu không có gì khác, bạn có thể so sánh nó với các phần trong sổ ghi chép - đơn giản hơn nếu bạn có "tất cả nội dung liên quan đến giao diện người dùng" ở đây và "tất cả nội dung liên quan đến trò chơi" ở đó.

Câu trả lời phức tạp hơn là việc phân chia công việc không chỉ thuận tiện mà còn rất quan trọng đối với việc quản lý sự phức tạp (và "quản lý sự phức tạp" gần như là tên của trò chơi khi nói đến lập trình). Các lớp hoặc các loại mô-đun khác, cho phép bạn "tách các mối quan tâm". Bạn không chỉ biết nơi để tìm "nội dung liên quan đến giao diện người dùng" mà bạn có thể chắc chắn rằng nếu bạn muốn thay đổi giao diện người dùng, bạn có thể chỉ cần đặt nó ở một nơi và bạn không phải lo lắng "bây giờ, đó có phải là nơi duy nhất tôi đặt phông chữ của mình thành Comic Sans không?". Và bạn có thể thực hiện một thay đổi và biết rằng ảnh hưởng của thay đổi đó chỉ là bất kỳ phạm vi (nhỏ) nào là phù hợp. Nếu mọi thứ đều nằm trong một lớp hoặc một mô-đun, thì về cơ bản mọi thứ đều là toàn cầu,

Trong trường hợp cụ thể của các lớp là một loại mô-đun phần mềm, cũng có rất nhiều hành vi được liên kết với một lớp và hầu hết các nhà phát triển trong mô hình hướng đối tượng đều thấy rất hữu ích khi có các tên có ý nghĩa liên quan đến các lớp có liên quan đến nhóm chức năng với nhau. Vì vậy, bạn có thể không thực sự có một UIlớp học, bạn có thể có một Buttonlớp học. Có toàn bộ kiến ​​thức và kỹ thuật liên quan đến thiết kế lớp hướng đối tượng và đó là cách phổ biến nhất để tổ chức các hệ thống lớn trong lập trình chính thống.


12

Đây là một câu hỏi hay! Đơn giản và cũng được hỏi. Chà ... câu trả lời không dễ hiểu cho một sinh viên đang học ngành khoa học máy tính và có lẽ không biết sâu về OO và có lẽ không có kinh nghiệm.

Vì vậy, tôi có thể trả lời bằng cách mô tả một kịch bản và khiến bạn tưởng tượng phần mềm đa lớp tốt hơn phần mềm nguyên khối (chỉ được tạo bởi một lớp):

  • Khả năng đọc : Việc duyệt và viết mã bên trong một tệp có 10000 dòng khó hơn nhiều so với một số tệp nhỏ và có tổ chức.
  • Khả năng sử dụng lại : Nếu bạn viết một lớp duy nhất, bạn có thể trượt trong sao chép mã . Điều này có nghĩa là nhiều dòng mã hơn và có thể có nhiều lỗi hơn (!)
  • Khả năng kiểm tra: Điều gì về kiểm tra một chức năng duy nhất? Nếu bạn cô lập một chức năng logic trong một lớp, cuộc sống của bạn sẽ dễ dàng hơn.
  • Khả năng duy trì mã : Bạn có thể sửa lỗi hoặc tăng cường chức năng với các lớp nhân ở một nơi duy nhất: Các lớp nhỏ đẹp.
  • Cấu trúc dự án : oooooh bạn có thể tưởng tượng một dự án xấu xí như thế nào chỉ với một tệp nguồn sẽ xuất hiện không?

Tôi thích câu trả lời của bạn và tôi vừa thực hiện một số thay đổi (vẫn cần được xem xét ngang hàng). Một điểm tôi bỏ lỡ là phát hiện dễ dàng hơn các thay đổi trong các hệ thống phiên bản Phần mềm như SVN / GIT. Nó cũng dễ dàng hơn để làm việc với nhiều lập trình viên song song cho một dự án.
Martin Thoma

Tôi muốn nói tách biệt mối quan tâm, sự gắn kết và tách rời là một khái niệm có phạm vi cao hơn so với kỷ luật của OOP. Các lập trình viên bắt buộc, logic và chức năng đều cố gắng cho sự gắn kết cao và khớp nối thấp.
sara

8

Có rất nhiều câu trả lời hay ở đây, và tôi chắc chắn đồng ý với chúng, nhưng tôi cảm thấy rằng có một điều đáng nói hơn.

Hiện tại, như bạn đã nói, bạn đang làm việc một mình trong dự án của mình. Tuy nhiên, trong tương lai, sẽ có lúc bạn cần phải làm việc trong một thiết lập nhóm. Trong những khoảng thời gian đó, bạn sẽ chia nhỏ công việc (có lẽ dự án sẽ khá lớn). Kết quả là có một vài lựa chọn khác nhau (tôi đoán thực sự là hai chính ). Bạn có thể có nhiều bản sao của một tệp và làm việc trên các "mảnh" riêng biệt của tệp và sau đó "kết hợp" chúng với bản sao và dán sau đó sửa đổi để các bộ phận của bạn có thể hoạt động cùng nhau hoặc bạn có thể chia tách các "mảnh" đó dễ dàng vào các lớp khác nhau và thảo luận về cách bạn sẽ viết các lớp đó và sử dụng kiến ​​thức đó để bắt đầu.

Vẫn sẽ cần phải làm việc để tích hợp tất cả các phần riêng biệt lại với nhau, nhưng nó sẽ dễ dàng hơn rất nhiều để duy trì. Bởi vì tệp x chứa mã y và đó là mã bạn biết bạn cần sửa đổi. Điều này đi vào điều tổ chức mà hầu hết các câu trả lời khác nói về.

Tổ chức một chương trình trong đầu của một người. Liên kết từ Giorgio


1
+1: Làm việc nhóm cũng rất quan trọng! Xem ví dụ paulgraham.com/head.html và đoạn văn có tiêu đề "Đừng có nhiều người chỉnh sửa cùng một đoạn mã."
Giorgio

@Giorgio Tôi chỉ lướt qua nó, nhưng có vẻ như là một tài nguyên tuyệt vời! Tôi sẽ thêm nó vào câu trả lời của mình đơn giản vì một số người có thể không xem trong phần bình luận. Chắc chắn sẽ cho nó đọc kỹ hơn một thời gian.
Sephallia

Điều này cũng áp dụng cho kiểm soát sửa đổi - làm việc trên các tệp riêng biệt có nghĩa là ít xung đột và hợp nhất hơn.
Phục hồi Monica

7

Trong thực tế những gì bạn đã làm là phát minh lại lập trình thủ tục. Xin lưu ý bạn hoàn toàn có thể viết phần mềm theo cách đó và trình biên dịch có thể sẽ không quan tâm. Trong nhiều năm, đây là cách mọi thứ được thực hiện cho đến khi máy tính nhanh hơn và các công cụ trở nên tốt hơn.

Điều đó đang được nói nếu bạn chia mã của mình thành các đơn vị logic khác nhau (Lớp, mô-đun, v.v.) là bạn có thể có rất nhiều đoạn mã ngắn dễ hiểu. có thể được duy trì sau này Nhiều mô-đun của tôi có ít hơn 20 dòng mã. Tôi biết rằng tất cả các mã về một chủ đề nhất định là ở một nơi cụ thể. Điều đó cũng có nghĩa là nếu có người khác tham gia dự án, họ sẽ có thời gian tìm đồ dễ dàng hơn nhiều.

Như Gerald Sussman nói rằng các chương trình của chúng tôi nên được viết trước để mọi người có thể đọc nó và thứ hai để máy tính có thể chạy nó. (Và nếu bạn chưa đọc "Cấu trúc và diễn giải các chương trình máy tính thì bạn nên)


4

Một người sử dụng nhiều lớp vì khi bạn tham gia vào những thứ lớn hơn, bạn sẽ thấy đơn giản là không có cách nào bạn có thể theo dõi mọi thứ khi đó là một đống mã lớn.

Bạn chỉ cần phân chia và chinh phục để xử lý nó.


3

Lập trình hướng đối tượng là ý tưởng tốt nhất duy nhất tôi từng thấy trong lập trình. Nhưng nó không phải là điều tốt nhất trong mọi trường hợp, bạn cần một chút kinh nghiệm lập trình để thấy được điểm của nó, và rất nhiều người đang tuyên bố sẽ làm OOP khi họ không.

Nếu bạn có thể tra cứu "lập trình có cấu trúc", có lẽ bạn sẽ tìm thấy thứ gì đó hữu ích hơn ngay lập tức. (Hãy chắc chắn rằng bạn đọc về già lập trình có cấu trúc. Về Old thường nhận mới, ý nghĩa fancier, và bạn không cần bất cứ điều gì ưa thích nào.) Đây là một khái niệm khá đơn giản về phá vỡ chương trình của bạn thành thủ tục con, đó là dễ dàng hơn rất nhiều so với phá vỡ nó thành các đối tượng. Ý tưởng là chương trình chính của bạn là một thói quen ngắn gọi chương trình con ("phương thức" trong Java) để thực hiện công việc. Mỗi chương trình con chỉ biết những gì nó được nói bởi các tham số của nó. (Một trong những tham số đó có thể là tên tệp, vì vậy bạn có thể gian lận một chút.) Vì vậy, nhìn vào tiêu đề của chương trình con / phương thức cho bạn ý tưởng nhanh về những gì nó làm, gần như trong nháy mắt.

Sau đó, tất cả các chương trình con được chia nhỏ tương tự cho đến một vài dòng mã mà không có bất kỳ lệnh gọi phương thức nào sẽ thực hiện công việc. Một chương trình chính gọi một vài phương thức, mỗi phương thức gọi một vài phương thức, mỗi phương thức .... xuống các phương thức đơn giản nhỏ thực hiện công việc. Bằng cách này, bạn có thể xem bất kỳ phần nào của một chương trình rất lớn (hoặc chương trình nhỏ) và nhanh chóng hiểu những gì nó làm.

Java được thiết kế rất đặc biệt cho những người đang viết mã Hướng đối tượng. Nhưng ngay cả chương trình OO khốc liệt nhất cũng sử dụng một số chương trình có cấu trúc và bạn luôn có thể lật đổ bất kỳ ngôn ngữ nào. (Tôi đã thực hiện OO ở đồng bằng C.) Vì vậy, bạn có thể thực hiện SP, hoặc bất cứ điều gì khác, bằng Java. Quên các lớp học và tập trung vào các phương thức lớn có thể được chia thành các phương thức nhỏ, có thể quản lý được. Tôi nên thêm rằng SP giúp ích rất nhiều cho phép bạn sử dụng lại mã của mình và cả với DRY (google nó, nhưng nó có nghĩa là nguyên tắc "Đừng lặp lại chính mình").

Hy vọng rằng tôi đã giải thích lý do và cách chia mã của bạn thành nhiều phần mà không cần đưa vào "các lớp". Chúng là một ý tưởng tuyệt vời và chỉ là thứ dành cho các trò chơi và Java là ngôn ngữ tuyệt vời cho OOP. Nhưng tốt hơn là nên biết tại sao bạn đang làm những gì bạn đang làm. Để OOP một mình cho đến khi nó bắt đầu có ý nghĩa với bạn.


0

Một trong những lợi ích là khả năng sử dụng lại. Một chương trình về cơ bản là một nhóm các hướng dẫn được nhóm lại với nhau. Bạn sẽ thấy rằng một số trong những hướng dẫn đó cũng phù hợp cho các chương trình khác.

Giả sử bạn làm một trò chơi nhảy. Sau này khi bạn quyết định làm một trò chơi đại bác, bạn thấy rằng phép tính vật lý mà bạn sử dụng trong trò chơi nhảy có ích ở đây.

Vì vậy, thay vì viết lại, hoặc tệ hơn là sao chép và dán nó vào chương trình mới, bạn biến nó thành một lớp. Vì vậy, lần tới khi bạn thực hiện một trò chơi khác trong đó cơ chế trò chơi yêu cầu vật lý, bạn có thể sử dụng lại nó. Tất nhiên điều này là quá đơn giản nhưng tôi hy vọng nó có ý nghĩa.


0

Trước hết, lưu ý rằng tôi là C ++ và Python, không phải Java, vì vậy một số điều này có thể không áp dụng đầy đủ. Vui lòng sửa cho tôi nếu tôi đưa ra một số giả định không chính xác về cách các lớp hoạt động trong Java.

Các lớp học chủ yếu hữu ích khi chúng được khởi tạo. Một lớp trong đó không có phiên bản nào được tạo ra thực sự chỉ là một không gian tên được tôn vinh. Nếu bạn sử dụng tất cả các lớp của mình theo cách này, thì thực sự, lợi ích của việc chuyển mọi thứ từ không gian tên sang không gian tên có vẻ không đáng kể - nhiều nhất, bạn sẽ giành chiến thắng bằng cách có một số dữ liệu riêng tư trong mỗi và từ đó gói gọn mọi thứ.

Tuy nhiên, đây không phải là nơi các lớp học tỏa sáng. Hãy xem xét Stringlớp: bạn có thể có tất cả các tính năng tương tự bằng cách sử dụng charmảng và một số hàm tĩnh. Tại thời điểm này, các chức năng cung cấp cho bạn thêm một chút đường an toàn và cú pháp. Bạn có thể viết string.length()thay vì length(char_array); Đó không phải là một vấn đề lớn, nhưng nhiều người vẫn thích nó. Hơn nữa, bạn biết rằng nếu ai đó đưa cho bạn String, nó được tạo bằng hàm Stringtạo và nó phải hoạt động với lengthhàm - nếu phiên bản mảng không thể xử lý một số ký tự thì nó không có cách nào ngăn bạn đưa nó vào đó .

Đó vẫn không phải là nó, mặc dù. Điểm mấu chốt là các lớp bó dữ liệu và các hàm hoạt động trên nó và trừu tượng hóa cả hai. Khi bạn có một phương pháp void f(Builder b)bạn biết bạn sẽ nhận được một Builder, và bạn có thể mong đợi rằng nó sẽ hỗ trợ một số hành vi nhất định. Tuy nhiên, bạn không biết gì về dữ liệu hoặc các hàm đang được thực thi - trên thực tế, các định nghĩa cho cả hai có thể chưa được viết khi bạn viết và biên dịch f.

Do đó, điểm đầu tiên cần hiểu là các lớp giúp cho việc truyền dữ liệu trở nên thuận tiện trong khi đảm bảo nó không bị hỏng. Điểm thứ hai là cả dữ liệu và chức năng (triển khai) nào của một đối tượng là một cái gì đó về đối tượng, không phải là thứ bạn có thể nói từ loại của nó.


0

Toàn bộ ý tưởng dựa trên một quy tắc chung có tên là chia và chinh phục .
Mô hình này có thể được sử dụng hầu hết mọi nơi; bạn chia một vấn đề thành những vấn đề nhỏ hơn và sau đó bạn giải quyết những vấn đề nhỏ, đơn giản và nổi tiếng này.
Chia chương trình của bạn thành các lớp là một trong những kiểu phân chia bắt đầu trở nên phổ biến trong thập kỷ qua. Trong mô hình lập trình này, chúng tôi mô hình hóa vấn đề của mình theo một số đối tượng và cố gắng giải quyết vấn đề bằng cách gửi tin nhắn giữa các đối tượng này.
Một số người có thể nói rằng phương pháp này dễ hiểu hơn, mở rộng và gỡ lỗi.
Mặc dù một số người không đồng ý :)


0

Nó không phải là về việc chia một chương trình thành các lớp mà là về cách bạn mô hình hóa ứng dụng của mình, tức là cách bạn hình dung các phần của ứng dụng. Chia tách mọi thứ chỉ là một cơ chế chúng ta sử dụng để hiểu những điều phức tạp hơn. Nó không chỉ với lập trình. Hãy tưởng tượng bảng mạch với nhiều dây vướng vào nhau, tạo thành một cấu trúc phức tạp với mỗi dây kết nối ở đâu đó (mã spaghetti). Bạn sẽ phải theo từng dây đến cuối để tìm ra các kết nối. Ngược lại, hãy tưởng tượng các dây được nhóm lại và mã hóa màu theo chức năng của chúng. Nó trở nên dễ dàng hơn rất nhiều để sửa chữa mọi thứ.

Ý tưởng là bạn không bắt đầu với một chương trình dài và sau đó chia nó thành các lớp. Nhưng trước tiên, bạn mô hình hóa ứng dụng của mình theo các đối tượng / lớp và sau đó kết nối chúng để xây dựng các ứng dụng.

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.