Có thực hành tốt nhất cho tổ chức gói (Java) không? [đóng cửa]


201

Cách đây ít lâu, tôi thấy một câu hỏi được trả lời ở đây liên quan đến tổ chức chi tiết của các gói java. Ví dụ, my.project.util, my.project.factory, my.project.servicevv

Tôi không thể tìm thấy nó bây giờ, vì vậy tôi cũng có thể đặt câu hỏi.

Có các thực tiễn tốt nhất liên quan đến việc tổ chức các gói trong Java và những gì diễn ra trong chúng?

Làm thế nào để bạn tổ chức các lớp học trong dự án Java của bạn?

Ví dụ, một dự án tôi đang làm việc với một vài người có một gói được gọi là đậu. Nó bắt đầu là một dự án chứa các loại đậu đơn giản, nhưng đã kết thúc (thông qua kinh nghiệm kém và thiếu thời gian) chứa mọi thứ (gần như). Tôi đã làm sạch chúng một chút, bằng cách đặt một số lớp nhà máy vào gói nhà máy (các lớp có phương thức tĩnh tạo ra hạt đậu) nhưng chúng ta có các lớp khác làm logic nghiệp vụ và các lớp khác xử lý đơn giản (không phải với logic nghiệp vụ) như truy xuất một thông báo cho một mã từ một tập tin thuộc tính.

Suy nghĩ và ý kiến ​​của bạn được đánh giá cao.


74
Tôi không đồng ý với việc kết thúc câu hỏi này. Tôi không đồng ý rằng các câu hỏi thực hành tốt nhất hầu như luôn dựa trên kinh nghiệm và ý kiến, tuy nhiên, tôi không đồng ý rằng những câu hỏi này nên được đóng trên Stack Overflow. Đây là mấu chốt của lập trình tốt, sử dụng thực tiễn tốt nhất và tìm giải pháp tốt nhất sử dụng những ý kiến ​​và kinh nghiệm này. Vui lòng mở lại câu hỏi này.
Cyntech

Tôi đề nghị bạn đọc cái này : isfice.com/blog/archives/5164 . TL; DR ... toàn bộ ý tưởng về "thực hành tốt nhất" đã bị phá vỡ. Tốt nhất, nó là một cách hiểu sai lầm nghiêm trọng, tệ nhất là nó hoàn toàn có hại.
Stephen C

Câu trả lời:


174

Tổ chức gói hoặc cấu trúc gói thường là một cuộc thảo luận sôi nổi. Dưới đây là một số hướng dẫn đơn giản để đặt tên và cấu trúc gói:

  • Thực hiện theo các quy ước đặt tên gói java
  • Cấu trúc các gói của bạn theo vai trò chức năng cũng như vai trò kinh doanh của chúng
    • Chia nhỏ các gói của bạn theo chức năng hoặc mô-đun của chúng. ví dụ com.company.product.modulea
    • Việc chia nhỏ hơn có thể dựa trên các lớp trong phần mềm của bạn. Nhưng đừng quá nhiệt tình nếu bạn chỉ có một vài lớp trong gói, vậy thì thật có ý nghĩa khi có mọi thứ trong gói. ví dụ com.company.product.module.webhoặc com.company.product.module.util, vv
    • Tránh quá nhiệt tình với cấu trúc, IMO tránh đóng gói riêng cho các trường hợp ngoại lệ, nhà máy, vv trừ khi có nhu cầu cấp bách.
  • Nếu dự án của bạn nhỏ, hãy giữ nó đơn giản với vài gói. ví dụ com.company.product.modelcom.company.product.util, v.v.
  • Hãy xem một số dự án nguồn mở phổ biến ngoài kia về các dự án Apache . Xem cách họ sử dụng cấu trúc, cho các dự án có kích thước khác nhau.
  • Đồng thời xem xét việc xây dựng và phân phối khi đặt tên (cho phép bạn phân phối api hoặc SDK của mình trong một gói khác, xem api của servlet)

Sau một vài thử nghiệm và thử nghiệm, bạn sẽ có thể đưa ra một cấu trúc mà bạn cảm thấy thoải mái. Đừng cố định theo một quy ước, hãy cởi mở với những thay đổi.


Cám ơn phản hồi của bạn. Đây phần lớn là những gì chúng tôi đã cố gắng bao gồm, nhưng rất nhiều mã không liên quan đã vào gói đậu của chúng tôi, đó là câu hỏi của tôi đến từ đâu.
Cyntech

2
Tôi đồng ý gói theo tính năng có ý nghĩa nhất. Tôi đã nghe một sự tương tự tuyệt vời một lần liên quan đến cấu trúc văn phòng công ty. Theo cách tiếp cận nhiều lớp, mỗi cá nhân trong mỗi cấp độ trong một công ty sẽ ngồi với nhau, tức là Giám đốc điều hành, quản lý, quản trị viên, nhân viên / công nhân đều ngồi trong các phần riêng biệt trong một tòa nhà. Cấu trúc này có thể không hiệu quả như một cách tiếp cận có tổ chức "tính năng". Tức là nếu Giám đốc bán hàng ngồi cùng với Giám đốc bán hàng ngồi cùng với các nhân viên bán hàng, tất cả đều ngồi với Quản trị viên bán hàng. Điều này cung cấp sự gắn kết tốt hơn giữa các bộ phận khi tổ chức theo cách này.
alex

Đồng ý với quan điểm của bạn. Chỉ cần một điểm để làm nổi bật về tên công ty trong gói một số lần công ty được bán sản phẩm. Quản lý muốn xóa tên công ty. Đó có thể là chi phí.
Tushar D

183

Tôi tổ chức các gói theo tính năng , không phải theo mẫu hoặc vai trò thực hiện. Tôi nghĩ các gói như:

  • beans
  • factories
  • collections

là sai.

Tôi thích, ví dụ:

  • orders
  • store
  • reports

để tôi có thể ẩn chi tiết thực hiện thông qua khả năng hiển thị gói . Nhà máy của các đơn đặt hàng nên có trong ordersgói để chi tiết về cách tạo đơn hàng được ẩn đi.


10
Bài đăng này làm cho một điểm tốt về khả năng hiển thị gói. Tôi chưa bao giờ thấy phạm vi gói Java được sử dụng, nhưng cấu trúc gói phù hợp có thể cho phép các nhà phát triển tận dụng tốt hơn nó.
Jpnh

23
Điều này là chính xác, nhưng rất ít nhà phát triển làm điều này. Các gói phải là các bộ sưu tập các lớp gắn kết, một số trong đó chỉ hiển thị trong gói. Điều đó sẽ giảm thiểu việc ghép nối giữa các lớp không nên được ghép bởi vì chúng liên quan đến các tính năng khác nhau. Cách tiếp cận theo từng lớp, không tận dụng các công cụ sửa đổi khả năng hiển thị của gói và các gói trong dự án như vậy có độ gắn kết thấp và mức độ khớp nối cao giữa các gói.
Nate Reed

Bạn có ví dụ về điều này? Tôi đang sử dụng Spring-MVC tôi thấy khó tổ chức nó theo tính năng / mô-đun vì spring sử dụng config xml.
Eric Huang

2
@onof Tôi cũng tổ chức mã của mình theo tính năng nhưng thực tiễn tốt nhất cho các lớp cơ sở được chia sẻ bởi tất cả các tính năng là gì?
Marc

Tôi đã theo phong cách đầu tiên. nhưng bây giờ tôi phải nhảy từ gói này sang gói khác khi làm việc với các lớp. nó thực sự làm cho một kinh nghiệm xấu Bây giờ tôi đang chuyển sang phong cách thứ hai bởi vì tôi nghĩ sẽ dễ dàng hơn để theo dõi các lớp liên quan với nhau.
M.kazem Akhÿ

40

Câu trả lời ngắn: Một gói cho mỗi mô-đun / tính năng, có thể với các gói phụ. Đặt những thứ liên quan chặt chẽ với nhau trong cùng một gói. Tránh phụ thuộc vòng tròn giữa các gói.

Câu trả lời dài: Tôi đồng ý với hầu hết bài viết này


2
gói phụ phá vỡ đóng gói. Một "gói phụ" thực sự là một gói hoàn toàn độc lập với chính nó
Ricardo Gamba

21

Tôi thích tính năng trước các lớp, nhưng tôi đoán nó phụ thuộc vào dự án của bạn. Hãy xem xét lực lượng của bạn:

  • Phụ thuộc
    Hãy thử giảm thiểu phụ thuộc gói, đặc biệt là giữa các tính năng. Trích xuất API nếu cần thiết.
  • Tổ chức nhóm
    Trong một số tổ chức, các nhóm làm việc trên các tính năng và trong các nhóm khác trên các lớp. Điều này ảnh hưởng đến cách tổ chức mã, sử dụng nó để chính thức hóa API hoặc khuyến khích hợp tác.
  • Triển khai và phiên bản
    Đưa mọi thứ vào một mô-đun giúp cho việc triển khai và phiên bản đơn giản hơn, nhưng việc sửa lỗi khó hơn. Chia tách mọi thứ cho phép kiểm soát tốt hơn, khả năng mở rộng và tính sẵn sàng.
  • Đáp ứng để thay đổi
    Mã được tổ chức tốt sẽ thay đổi đơn giản hơn nhiều so với một quả bóng lớn.
  • Kích thước (người và dòng mã)
    Càng lớn càng cần phải chính thức hóa / tiêu chuẩn hóa.
  • Tầm quan trọng / chất lượng
    Một số mã quan trọng hơn các mã khác. API nên ổn định hơn sau đó thực hiện. Do đó, nó cần phải được phân tách rõ ràng.
  • Mức độ trừu tượng và điểm nhập cảnh
    Người ngoài có thể biết mã đó là về cái gì và bắt đầu đọc từ đâu khi nhìn vào cây gói.

Thí dụ:

com/company/module
  + feature1/
    - MainClass          // The entry point for exploring
    + api/               // Public interface, used by other features
    + domain/
      - AggregateRoot
      + api/             // Internal API, complements the public, used by web
      + impl/ 
    + persistence/       
    + web/               // presentation layer 
    + services/          // Rest or other remote API 
    + support/            
  + feature2/
  + support/             // Any support or utils used by more than on feature
    + io
    + config
    + persistence
    + web

Đây chỉ là một ví dụ. Nó là khá chính thức. Ví dụ, nó định nghĩa 2 giao diện cho Feature1 . Thông thường điều đó là không bắt buộc, nhưng có thể là một ý tưởng tốt nếu được sử dụng khác nhau bởi những người khác nhau. Bạn có thể để API nội bộ mở rộng công khai.

Tôi không thích tên 'impl' hoặc 'support', nhưng chúng giúp tách biệt những thứ ít quan trọng hơn khỏi tên miền quan trọng (tên miền và API). Khi nói đến việc đặt tên tôi thích càng cụ thể càng tốt. Nếu bạn có một gói được gọi là 'utils' với 20 lớp, hãy chuyển StringUtilssang hỗ trợ / chuỗi, HttpUtilđể hỗ trợ / http, v.v.


13

Có các thực tiễn tốt nhất liên quan đến việc tổ chức các gói trong Java và những gì diễn ra trong chúng?

Không hẳn là không. Có rất nhiều ý tưởng, và rất nhiều ý kiến, nhưng "thực tiễn tốt nhất" thực sự là sử dụng ý thức chung của bạn!

(Vui lòng đọc Không có Thực tiễn Tốt nhất để biết về quan điểm về "thực tiễn tốt nhất" và những người quảng bá chúng.)

Tuy nhiên, có một hiệu trưởng có thể được chấp nhận rộng rãi. Cấu trúc gói của bạn sẽ phản ánh cấu trúc mô-đun (không chính thức) của ứng dụng của bạn và bạn nên đặt mục tiêu giảm thiểu (hoặc lý tưởng nhất là tránh hoàn toàn) mọi phụ thuộc theo chu kỳ giữa các mô-đun.

. phụ thuộc giữa các gói / liên mô-đun có nghĩa là toàn bộ mớ hỗn độn được kết nối phải là một tạo tác Maven.)

Tôi cũng nên thêm rằng có một chấp nhận rộng rãi thực hành tốt nhất cho tên gói. Và đó là tên gói của bạn nên bắt đầu bằng tên miền của tổ chức của bạn theo thứ tự ngược lại. Nếu bạn tuân theo quy tắc này, bạn sẽ giảm khả năng xảy ra sự cố do tên lớp (đầy đủ) của mình đụng độ với những người khác '.


9

Tôi đã thấy một số người quảng cáo 'gói theo tính năng' hơn 'gói theo lớp' nhưng tôi đã sử dụng khá nhiều cách tiếp cận trong nhiều năm và thấy 'gói theo lớp' tốt hơn nhiều so với 'gói theo tính năng'.

Hơn nữa, tôi đã thấy rằng một gói lai: 'gói theo mô-đun, lớp sau đó có tính năng' chiến lược hoạt động cực kỳ tốt trong thực tế vì nó có nhiều ưu điểm của 'gói theo tính năng':

  • Thúc đẩy việc tạo các khung có thể tái sử dụng (các thư viện có cả khía cạnh mô hình và giao diện người dùng)
  • Cho phép triển khai lớp cắm và phát - hầu như không thể với 'gói theo tính năng' vì nó đặt các cài đặt lớp trong cùng gói / thư mục làm mã mô hình.
  • Nhiều hơn nữa ...

Tôi giải thích sâu ở đây: Cấu trúc và tổ chức tên gói Java nhưng cấu trúc gói tiêu chuẩn của tôi là:

revdomain.moduleType.moduleName.layer. [layerImpl] .feature.subfeatureN.subfeatureN + 1 ...

Ở đâu:

revdomain Đảo ngược tên miền, ví dụ com.mycompany

moduleType [ứng dụng * | khung | sử dụng]

moduleName, ví dụ myAppName nếu loại mô-đun là một ứng dụng hoặc 'tài chính' nếu là khung kế toán

lớp [mô hình | ui | kiên trì | bảo mật, v.v.]

layerImpl, ví dụ: wicket, jsp, jpa, jdo, hibernate (Lưu ý: không được sử dụng nếu lớp là mô hình)

tính năng, ví dụ: tài chính

subfeatureN, vd.

subfeatureN + 1 ví dụ: khấu hao

* Đôi khi 'ứng dụng' bị bỏ qua nếu moduleType là một ứng dụng nhưng việc đặt nó vào đó làm cho cấu trúc gói nhất quán trên tất cả các loại mô-đun.


5

Tôi không nhận thức được các tiêu chuẩn thực hành cho tổ chức gói. Tôi thường tạo ra các gói bao gồm một số phổ rộng hợp lý, nhưng tôi có thể phân biệt trong một dự án. Ví dụ, một dự án cá nhân mà tôi hiện đang làm việc có một gói dành cho các điều khiển UI tùy chỉnh của tôi (có đầy đủ các lớp swing lớp phân lớp). Tôi đã có một gói dành riêng cho công cụ quản lý cơ sở dữ liệu của mình, tôi đã có một gói cho một nhóm người nghe / sự kiện mà tôi đã tạo, v.v.

Mặt khác, tôi đã có một đồng nghiệp tạo ra một gói mới cho hầu hết mọi thứ anh ta đã làm. Mỗi MVC khác nhau mà anh ta muốn có gói riêng và dường như một bộ MVC là nhóm duy nhất của các lớp được phép ở trong cùng một gói. Tôi nhớ lại tại một thời điểm anh ta có 5 gói khác nhau, mỗi gói có một lớp duy nhất trong đó. Tôi nghĩ rằng phương pháp của anh ấy hơi cực đoan (và nhóm buộc anh ấy phải giảm số lượng gói của mình khi chúng tôi đơn giản không thể xử lý nó), nhưng đối với một ứng dụng không cần thiết, vì vậy sẽ đặt mọi thứ vào cùng một gói. Đó là một điểm cân bằng mà bạn và đồng đội phải tự tìm kiếm.

Một điều bạn có thể làm là cố gắng lùi lại và suy nghĩ: nếu bạn là thành viên mới được giới thiệu cho dự án, hoặc dự án của bạn được phát hành dưới dạng nguồn mở hoặc API, việc tìm kiếm những gì bạn muốn sẽ dễ dàng / khó khăn như thế nào? Bởi vì đối với tôi, đó là điều tôi thực sự muốn từ các gói: tổ chức. Tương tự như cách tôi lưu trữ các tệp trong thư mục trên máy tính của mình, tôi hy vọng có thể tìm lại chúng mà không phải tìm kiếm toàn bộ ổ đĩa của mình. Tôi xin lỗi để có thể tìm thấy lớp tôi muốn mà không phải tìm kiếm danh sách tất cả các lớp trong gói.

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.