Есть два лагеря: функциональное и техническое именование.
Один, как:
org.example.customer
org.example.account
Другой, как:
org.example.dao
org.example.service
Мне лично нравится иметьинтерфейс и реализации в одном месте и делают только интерфейс общедоступным и упаковывать по функциональности, так как пакеты имеют более высокую согласованность таким образом.
При увеличении размера вы можете разделить пакеты, например, org.example.customer.dao
, org.example.customer.service
и org.example.customer.ui
.(Технически это то же самое, что и org.example.dao.customer.dao
, org.example.service.customer
и org.example.ui.customer
, поскольку пакеты Java не являются вложенными.)
Для вашего примера я бы начал с:
org.example.customer.CustomerDao
org.example.customer.DatabaseCustomerDao (package private)
org.example.account.AccountDao
org.example.account.DatabaseAccountDao (package private)
Чтобы сделать пакет реализации закрытым, вам нужна фабрика для создания экземпляров.Если вы используете DI.DI-framework реализует для вас фабрику, и вы можете внедрить экземпляры в классы пользователей, которые зависят только от контракта интерфейса.