Вы должны разделять задачи управления IndexCards и самими IndexCards из-за принципа единой ответственности.Кроме того, ListAdministrator должен обрабатывать все, что касается управления IndexCards, а также удаления и создания управляемых объектов.
Имя ListAdministrator почему-то не соответствует сути, поскольку не управляет списками, возможно, использует что-то вроде IndexCardRegistry.
Чтобы справиться с параллелизмом, вы можете использовать ConcurrentMap в качестве основного хранилища данных.
Наличие в ListAdministrator всех статических устройств может пригодиться, если ваши IndexCards нуждаются в доступе к нему или другим IndexCards, но это не лучший дизайн.Они должны знать в любом случае?Насколько я понимаю, IndexCards могут быть простыми POJO, которые содержат только данные и не содержат никакой логики.
С другой стороны, в случае полностью статического ListAdministrator вы не сможете использовать два экземпляра управляемых объектов одновременно без серьезного рефакторинга кода.Даже если вы и не ожидаете этого сегодня, в будущих проектах может пригодиться четко определенный реестр объектов, который может обрабатывать любой объект.Поэтому я бы предпочел использовать реальные экземпляры для ListAdministrator (и программировать на его интерфейс, чтобы оставаться гибким).
Более подробно со ссылкой на ваши комментарии:
Идея этого подхода состоит в том, чтобы четко разделить проблемы, что сделает будущие изменения в вашем коде осуществимыми в случае, еслиПроект растет (большинство проектов, как правило, делают это).Насколько я понимаю, ListAdministrator должен управлять вашими IndexCards.В некотором смысле это то же самое, что и работа Object Relational Mappers, но на данный момент ваша база данных является HashMap.Если вы создадите интерфейс для ListAdministrator, вы даже можете поменять HashMap с базой данных, не меняя ее клиентов.
При втором исследовании вашего кода я обнаружил, что IndexCards не только хранит данные, но и имеет методыобновить данные.Это представляет собой еще одно нарушение принципа единой ответственности, и его следует устранить.Если ListAdministrator предоставит метод обновления для данной карты IndexCard, он может использоваться любым количеством различных клиентов, о которых вы только можете подумать, без изменения какого-либо кода за API ListAdministrators.Ваш первый клиент будет интерфейсом командной строки, который вы уже запрограммировали, следующим может быть веб-служба.
С полностью статическим ListAdministrator у вас есть один статический класс, который управляет одним набором статических данных.Он всегда будет иметь дело только с IndexCards, все, что вы добавите, окажется в той же HashMap (если разрешено / совместимо).Каждая часть вашего приложения с доступом к классу ListAdministrator будет иметь полный доступ к данным.Если вам нужен другой ListAdministrator (для обработки создания, удаления, обновления, поиска) для другого типа, вам придется реорганизовать все, чтобы приспособиться к этому или начать дублирование кода.Почему бы не создать решение, основанное на экземплярах?У вас будет свой репозиторий для IndexCards, и вы сможете добавлять новые репозитории по своему желанию.
Может быть, это чрезмерная разработка для вашего варианта использования, но при четком разделении обязанностей вы обнаружите, что многие расширения вашего кода будут ортогональными (не влияющими на существующий код), и именно здесь действительно веселоначинается.И как вы хотите практиковать это, если не с небольшими проектами.
Подробнее о причине использования интерфейсов для гибкого кода (в ответ на последний комментарий)
Краткий ответ: всегда используйте код для интерфейса (как указано в многочисленных статьях и Java-книгах).Но почему?
Интерфейс Java подобен договору между классом и его клиентами.Он определяет некоторые методы, но не реализует их сам.Для реализации интерфейса вы определяете класс с помощью class XYZ implements SomeInterface
, а исходный код класса делает все, что сочтет целесообразным, чтобы ответить на методы, определенные в интерфейсе.Вы пытаетесь сохранить интерфейс небольшим, чтобы он содержал только основные методы, потому что чем меньше интерфейс, тем меньше методов вы должны учитывать при внесении изменений.
В Java будет распространена идиомаопределить List<T>
тип возвращаемого значения (интерфейс) для метода, который, скорее всего, будет ArrayList
(конкретный класс), но также может быть LinkedList
(другой конкретный класс) или что-либо еще, что реализуетинтерфейс списка.Просто возвращая интерфейс List, вы не позволяете вашему клиенту использовать другие методы возвращаемого в противном случае конкретного класса, что значительно уменьшит вашу свободу изменять внутреннюю реализацию вашего ListProvider.Вы скрываете внутреннюю реализацию, но соглашаетесь вернуть что-то, удовлетворяющее данному интерфейсу.Если вы хотите уступить еще меньшим обязательствам, вы можете вернуть интерфейс Iteratable
вместо List
.
Оформить заказ Java API, вы найдете стандартные классы, такие как ArrayList
, реализующие множество интерфейсов.Вы всегда можете использовать ArrayList
для внутреннего использования и вернуть его как наименьший интерфейс для выполнения работы.
Вернуться к вашему проекту.Было бы важно сослаться на Реестр (ListAdministrator) через его интерфейс, а не на конкретный класс.Интерфейс будет определять такие методы, как
interface IndexCardRegistry {
void delete(Long id) throws IllegalAccessException;
void update(Long id, Some data) throws IllegalAccessException;
// ...
}
То, что он делает, не имеет значения для клиента, он просто надеется, что все идет хорошо.Поэтому, если клиент вызывает метод обновления репозиториев, он будет полагаться на репозиторий для обновления целевой IndexCard.Хранилище может хранить данные по своему усмотрению, в HashMap
, в List
или даже в базе данных, это не будет иметь значения для клиентов.
class IndexCardMapBasedRegistry implements IndexCardRegistry {
private Map store = new HashMap();
void delete(Long id) throws IllegalAccessException {
// code to remove the IndexCard with id from the hashmap
}
void update(Long id, Some data) throws IllegalAccessException {
// code to get the IndexCard with id from
// the hashmap and update its contents
}
// ...
}
Теперь новая итерация впри создании реестра вы меняете IndexCardMapBasedRegistry на новый
class IndexCardDatabaseRegistry implements IndexCardRegistry {
private Database db;
void delete(Long id) throws IllegalAccessException {
// code to remove the IndexCard with id from the database
}
void update(Long id, Some data) throws IllegalAccessException {
// code to update the IndexCard with id in the database
}
// ...
}
IndexCardRegistry indexCards = new IndexCardMapBasedRegistry();
становится IndexCardRegistry indexCards = new IndexCardDatabaseRegistry();
Клиент вообще не должен меняться, но реестр сможет обработатьколичество карточек IndexCards, которые в противном случае унесли бы память вашего компьютера.