Каков наилучший способ разбиения класса, когда его функциональные возможности должны по-разному использоваться различными классами? Надеюсь, следующий пример прояснит вопрос:)
У меня есть класс Java, который обращается к одному месту в каталоге, позволяя внешним классам выполнять операции чтения / записи в него. Операции чтения возвращают статистику использования в каталоге (например, доступное дисковое пространство, количество записей и т. Д.); Операции записи, очевидно, позволяют внешним классам записывать данные на диск. Эти методы всегда работают в одном и том же месте и получают свою конфигурацию (например, какой каталог использовать, минимальное дисковое пространство и т. Д.) Из внешнего источника (переданного конструктору).
Этот класс выглядит примерно так:
public class DiskHandler {
public DiskHandler(String dir, int minSpace) {
...
}
public void writeToDisk(String contents, String filename) {
int space = getAvailableSpace();
...
}
public void getAvailableSpace() {
...
}
}
Там происходит немного больше, но этого будет достаточно.
Этот класс должен по-разному вызываться двумя внешними классами. Один класс нуждается в доступе к операциям чтения; другому нужен доступ как к операциям чтения, так и записи.
public class DiskWriter {
DiskHandler diskHandler;
public DiskWriter() {
diskHandler = new DiskHandler(...);
}
public void doSomething() {
diskHandler.writeToDisk(...);
}
}
public class DiskReader {
DiskHandler diskHandler;
public DiskReader() {
diskHandler = new DiskHandler(...);
}
public void doSomething() {
int space = diskHandler.getAvailableSpace(...);
}
}
На этом этапе оба класса совместно используют один и тот же класс, но класс, который должен только читать, имеет доступ к методам записи.
Решение 1
Я мог бы разбить этот класс на две части. Один класс будет обрабатывать операции чтения, а другой - записи:
// NEW "UTILITY" CLASSES
public class WriterUtil {
private ReaderUtil diskReader;
public WriterUtil(String dir, int minSpace) {
...
diskReader = new ReaderUtil(dir, minSpace);
}
public void writeToDisk(String contents, String filename) {
int = diskReader.getAvailableSpace();
...
}
}
public class ReaderUtil {
public ReaderUtil(String dir, int minSpace) {
...
}
public void getAvailableSpace() {
...
}
}
// MODIFIED EXTERNALLY-ACCESSING CLASSES
public class DiskWriter {
WriterUtil diskWriter;
public DiskWriter() {
diskWriter = new WriterUtil(...);
}
public void doSomething() {
diskWriter.writeToDisk(...);
}
}
public class DiskReader {
ReaderUtil diskReader;
public DiskReader() {
diskReader = new ReaderUtil(...);
}
public void doSomething() {
int space = diskReader.getAvailableSpace(...);
}
}
Это решение предотвращает доступ классов к методам, которые им не нужны, но также нарушает инкапсуляцию. Первоначальный класс DiskHandler был полностью автономным и требовал только параметров конфигурации через один конструктор. Разбивая функциональность на классы чтения / записи, они оба связаны с каталогом, и оба должны быть созданы с соответствующими значениями. По сути, мне не важно дублировать проблемы.
Решение 2
Я мог бы реализовать интерфейс, обеспечивающий только операции чтения, и использовать его, когда классу нужен только доступ к этим методам.
Интерфейс может выглядеть примерно так:
public interface Readable {
int getAvailableSpace();
}
Класс Reader будет создавать экземпляр объекта следующим образом:
Readable diskReader;
public DiskReader() {
diskReader = new DiskHandler(...);
}
Это решение кажется хрупким и может привести к путанице в будущем. Это не гарантирует, что разработчики будут использовать правильный интерфейс в будущем. Любые изменения в реализации DiskHandler могут также потребовать обновления интерфейса и доступа к классам. Мне нравится это лучше, чем предыдущее решение, но не намного.
Честно говоря, ни одно из этих решений не кажется идеальным, но я не уверен, что одно предпочтение следует отдавать другому. Я действительно не хочу разбивать исходный класс, но я также не знаю, сильно ли интерфейс меня покупает в долгосрочной перспективе.
Есть ли другие решения, которые мне не хватает?