Структурирование java классов, чтобы избежать instanceOf - PullRequest
1 голос
/ 02 мая 2020

Я пытаюсь создать приложение в java, которое загружает и настраивает ряд различных шейдеров GLSL. В настоящее время у меня есть что-то похожее на приведенное ниже, но в итоге, вероятно, будет гораздо больше (более 30) подобных классов - каждый загружает отдельный шейдер

В идеале я хотел бы иметь возможность поместить классы шейдеров в список и связать их до GUI, чтобы параметры шейдера можно было получать и обновлять. Помимо одного и того же логика c (загрузка файла GLSL и возвращение PShader), переменные (и методы получения / установки) могут сильно отличаться для каждого класса (например, некоторые шейдеры GLSL, которые я хочу использовать, не имеют переменных, в то время как другие могут иметь одну или несколько переменных - float, boolean, int et c).

Я мог бы иметь некоторый базовый класс и расширить класс для обработки различных переменных, но это все еще, вероятно, приводит меня к в какой-то момент приходится управлять какой-то проверкой типов / используя кучу операторов instanceOf. Я изо всех сил пытаюсь увидеть, как полиморфизм может быть легко применен здесь. Я посмотрел на java отражение, но это не слишком меня задело, и я рассматривал различные шаблоны проектирования.

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

public class ChromaColor {

    private Shader shader;
    private float smoothing;

    public Chroma(){
        shader = loadShader("chroma.glsl");
        setSmoothing(0.1F);
    }

    public Chroma setSmoothing(float f) {
        if(shader != null) shader.set("smoothing", f);
        this.smoothing = f;
        return this;
    }

    public float getSmoothing() {
        return smoothing;
    }

    public Shader shader() {
        return shader;
    }

}

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Помимо одинаковых общих логи c (загрузка файла GLSL и возврат PShader), переменные (и методы получения / установки) могут быть совершенно разными для каждого класса

. ...

Я изо всех сил пытаюсь понять, как полиморфизм может быть легко применен здесь. Я посмотрел на java отражение, но это меня не задело слишком далеко, и я рассматривал различные шаблоны проектирования.

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

Либо вы определяете класс рендеринга / обработки по классам для обработки.
Преимущество : проверки во время компиляции.
Недостаток : много повторяющегося кода для write.

Или вы используете отражение для извлечения поля для получения / установки в GUI.
Advantage : гораздо меньше кода для записи.
Недостаток : нет проверки во время компиляции.
Примечание 1) использование отражений для извлечения всех получателей / установщиков может извлекать приватные поля, которые вы не хотите открывать для GUI.
Если это так, аннотирование полей для включения или исключения может быть способом решения этой проблемы.
Примечание 2) отсутствие проверки во время компиляции может быть уменьшено, если вы пишете модульные тесты (возможно, параметризованные тесты), которые проверяют свойства экземпляров различные классы для обработки вполне могут быть прочитаны / записаны GUI.

0 голосов
/ 02 мая 2020

Как насчет использования экземпляра java.util.Properties в качестве единственного параметра для конфигурации Shader? Или другой тип java.util.Map?

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

Это позволит вам максимально использовать код. Это позволило бы также иметь геттеры и сеттеры. Посмотрите на классы в java.time для примера, как это могло бы выглядеть…

Это может выглядеть так:

public interface IChromaColors
{
  Set<Parameter> getParameters();

  void configure( Map<Parameter,Object> values );

  Object get( Parameter parameter );

  void set( Parameter parameter, Object value );
}

Parameter может выглядеть так:

public interface Parameter<T>
{
  String getName();

  Class<T> getType();

  boolean validate( T value );
}

Теперь ваш класс может выглядеть так:

public class ChromaColor implements IChromaColor
{
    private Map<Parameter,Object> m_Values;
    private Set<Parameter> m_ValidValues;
    private Shader shader;

    public Chroma( Map<Parameter,Object> values )
    {
        shader = loadShader("chroma.glsl");
        m_ValidValues = Set.of( SmoothingParameter );

        m_Values = values;
        if( !m_Values.contains( SmootingParameter ) ) 
        {
           m_Values.put( SmoothingParameter, Float.valueOf( 0.1F ) );
        }
        configure( m_Values );
    }

    public Chroma set( Parameter parameter, Object value
    {
        if( m_ValidValues.contains( parameter )
        {
           …
        }
        return this;
    }

    public Object get( Parameter parameter )
   {
        return m_Values.get( parameter );
    }

    public Shader shader() {
        return shader;
    }

}

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

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