Подтвердить что ты не робот

Java: статические абстрактные (снова) - лучшая практика, как работать

Теоретически я понимаю, почему в Java нет абстрактного статического, как объясняется, например, в Почему статические методы не могут быть абстрактными в Java.

Но как решить такую ​​проблему?

В моем приложении используются файлы нескольких типов, которые я хочу назначить статическим свойствам, например, описание этого типа файла (например, "файл данных", а другой - "файл конфигурации" и т.д.). Очевидно, я бы поставил это в статическую String, чтобы описание было доступно без инстанцирования файла (полезно для GUI f.i.). С другой стороны, очевидно, что все типы файлов должны иметь некоторые общие методы, такие как getStatus(), которые, очевидно, я хочу наследовать от общего суперкласса MyFileType.

getDescription(), конечно, будет абстрактным в суперклассе.

Пробовал использовать комбинацию суперкласса и интерфейса, но аналогичная проблема: статическая реализация абстрактного метода не допускается.

Как решает Java-гуру? Это действительно такая плохая реализация, которую я хочу создать?

Большое спасибо, Philipp

4b9b3361

Ответ 1

Чтобы переформулировать проблему: вы хотите, чтобы ваши классы типа каждого файла имели статически доступную информацию о типе (например, имя и описание).

Мы можем легко получить туда часть: создать отдельный класс для вашей информации о типе и иметь статический экземпляр этого (соответствующим образом созданный экземпляр) в каждом классе каждого типа.

package myFileAPI;

public class TypeInfo { 
    public final String name;
    public final String description;

    public TypeInfo(String name, String description) {
        this.name = name;
        this.description = description;
    }
}

и, скажем:

package myFileAPI;

public class TextFile {
    public static final TypeInfo typeInfo
                   = new TypeInfo("Text", "Contains text.");
}

Затем вы можете делать такие вещи, как:

System.out.println(TextFile.typeInfo.name);

(Конечно, вы могли бы также использовать геттеры в TypeInfo для инкапсуляции базовых строк.)

Однако, как вы сказали, мы действительно хотим, чтобы во время компиляции было установлено наличие определенного статического метода подписи во всех классах типа каждого файла, но "очевидный" путь проектирования приводит к требованию абстрактного статического метод в общем суперклассе, который не допускается.

Мы можем обеспечить это во время выполнения, хотя это может быть достаточно хорошим, чтобы обеспечить правильную кодировку. Введем суперкласс класса File:

package myFileAPI;

public abstract class File {

    public static TypeInfo getTypeInfo() {
        throw new IllegalStateException(
                    "Type info hasn't been set up in the subclass");
    }

}

Если TextFile теперь extends File, мы получим это исключение при вызове TextFile.getTypeInfo() во время выполнения, если TextFile не имеет метода одинаковой подписи.

Это довольно тонкий: код с TextFile.getTypeInfo() в процессе компиляции, даже если такого метода нет в TextFile. Несмотря на то, что статические методы привязаны во время компиляции, компилятор все еще может просматривать иерархию классов, чтобы определить статическую цель статического вызова компиляции.

Итак, нам нужен код вроде:

package myFileAPI;

public class TextFile extends File {

    private static final TypeInfo typeInfo
                      = new TypeInfo("Text", "Contains text.");

    // Shadow the superclass static method
    public static TypeInfo getTypeInfo() {
        return typeInfo;
    }

}

Обратите внимание, что мы по-прежнему shadowing метод суперкласса, и поэтому File.getTypeInfo() все равно может быть "бессмысленно" вызван.

Ответ 2

Это замечательное время, чтобы вытащить основную теорему разработки программного обеспечения:

Любая проблема может быть решена путем добавления другого слоя косвенности.

Проблема, которую вы имеете здесь, заключается в том, что файл содержит множество частей информации - тип файла, описание файла, содержимое файла и т.д. Я бы предложил разделить это на два класса - один класс, представляющий конкретный файл на диске и его содержимое, а второй - абстрактное описание некоторого типа файла. Это позволит вам обрабатывать класс типа файла полиморфно. Например:

public interface FileType {
     String getExtension();
     String getDescription();

     /* ... etc. ... */
}

Теперь вы можете создавать подклассы для каждого из типов файлов, которые вы используете:

public class TextFileType implements FileType {
     public String getExtension() {
         return ".txt";
     }
     public String getDescription() {
         return "A plain ol' text file.";
     }
     /* ... */
}

Затем у вас может быть большой репозиторий таких объектов, который позволит вам запрашивать их свойства без открытого файла этого типа. Вы также можете связать тип с каждым фактическим файлом, который вы используете, просто сохраняя ссылку FileType.

Ответ 3

Вопрос не достаточно ясен, чтобы дать объективный ответ. Так как я не могу дать вам рыбу, этот ответ больше похож на "Научить вас ловить рыбу"

Когда вы сталкиваетесь с такими проблемами дизайна, как эти, где вы думаете "duh..Now sure, почему такая простая вещь настолько сложна" чаще, чем нет, вы либо разрабатываете ее явно неправильно, либо вы по усложнениюсильные вещи. Если я правильно сочувствую, проблема дизайна кажется "общим требованием", но язык не позволяет это.

  • Отследить ваши шаги/решения по дизайну
  • задайте все "очевидные" и "вне курса", на которых вы основываете свой дизайн (вы используете довольно много из них выше).
  • посмотреть, можно ли упростить вещи ( не применять ни одну из концепций OO до крайности. Сделать компромиссы на основе ROI)

... и вы, скорее всего, придете к приемлемому ответу.

Если вы все еще этого не сделаете, отправьте назад классы и интерфейсы, которые, как вы думаете, хотите (с ошибками компиляции, поскольку язык не позволяет определенные вещи), и, возможно, мы сможем помочь вам настроить ваш дизайн.

Ответ 4

аннотации могут быть хорошими для вашей цели.

@FileProperties(desc="data file")
public class DataFile extends XFile { ... }

FileProperties props = DataFile.class.getAnnotation(FileProperties.class);
String desc = props.desc(); 

Доступ к информации по-прежнему требует отражения, однако это немного лучше, чем использование статического поля/метода.

Компилятор Java не гарантирует, что все подклассы аннотируются как таковые. Вы можете добавить свою логику в компилятор (используя обработку аннотаций), но это слишком сложно. Хорошо проверить его во время выполнения.

Update:

Это также возможно:

@FileInfoClass ( DataFileInfo.class )
@public class DataFile

Ответ 5

Похоже, вам нужно использовать синглтон. В принципе, вы вызываете статический метод типа MyFileTypes.getDataFileInstance(), который создает один экземпляр (или повторно использует, если он уже создан) объекта, и когда вы сначала создаете его, установите "константы" по мере необходимости. Я посмотрю, смогу ли я найти вам хороший пример, но ваш пост не совсем понятен, как вы хотите его использовать.

Ответ 6

Вы можете создать класс FileMetadata со всей необходимой информацией. Когда приложение запускается, вы можете создавать экземпляры FileMetadata и сохранять для них статические указатели, чтобы вы могли обращаться к ним из любого места в JVM.

Таким образом вы помещаете абстрактный материал в фактические экземпляры; все, что не требует абстрактной семантики, может быть статическим...

Ответ 7

Я не знаю, как это разрешит гуру java, но я бы, вероятно, создал ресурсный пакет со всеми описаниями в файл свойств следующим образом:

com.bigcompany.smallapp.files.DataFile=Data file
com.bigcompany.smallapp.files.ConfigFile=Config file

Обработка пакета удобно размещать в суперклассе или в другом месте.

Другой вариант - использовать отражение для доступа к статическим полям в каждом подклассе, но тогда вам нужно убедиться, что все подклассы имеют статическое поле с тем же именем.

Могут быть и другие варианты, даже рефакторинг кода, так что подтипы не представлены отдельным классом каждый, но в целом нет водонепроницаемого решения.

Ответ 8

Вместо того, чтобы статические свойства на самом деле находились в статических свойствах, поставьте ссылку на MyFileTypeDescription как статическое свойство.

то есть.

class MyFileType {
   static MyFileTypeDescription description;
   ...
   <your regular attributes>
}
abstract class MyFileTypeDescription {
  String name;
  abstract String getDescription();
}

Что-то вроде этого, если я правильно понял вашу проблему.

Ответ 9

У меня в основном была такая же проблема.

Вы можете посмотреть на решения, предложенные мне в моем вопросе

Мне понравилась идея Божо, но, по его словам, это была плохая идея.:) Я полагаю, лучшие программисты могут объяснить, почему это так. Решение Ralph и Jon Skeet также работает.