Java: статическая абстракция (снова) - лучшая практика, как обойти - PullRequest
24 голосов
/ 19 января 2011

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

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

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

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

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

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

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

Ответы [ 9 ]

30 голосов
/ 30 ноября 2012

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

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

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 () все еще может вызываться «бессмысленно».

7 голосов
/ 19 января 2011

Звучит как прекрасное время для извлечения фундаментальной теоремы разработки программного обеспечения:

Любую проблему можно решить, добавив еще один слой косвенности.

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

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 голосов
/ 19 января 2011

аннотации могут подойти для вашей цели.

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

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

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

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

Обновление:

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

@FileInfoClass ( DataFileInfo.class )
@public class DataFile
3 голосов
/ 19 января 2011

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

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

  • Отслеживание ваших шагов / решений по дизайну
  • ставит под сомнение все «очевидное» и «несоответствующее», на котором вы основываете свой дизайн (вы используете немало из них выше)
  • посмотрите, можно ли что-то упростить ( не берителюбой из концепций ОО до предела . Идите на компромиссы, основанные на ROI)

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

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

0 голосов
/ 05 февраля 2011

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

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

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

0 голосов
/ 19 января 2011

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

т.е.

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

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

0 голосов
/ 19 января 2011

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

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

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

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

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

0 голосов
/ 19 января 2011

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

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

0 голосов
/ 19 января 2011

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

...