Какова связь между семейством компонентов, типом компонента и типом рендерера? - PullRequest
22 голосов
/ 10 ноября 2011

Когда я изучал разработку пользовательских компонентов в JSF, меня запутали отношения между семейством компонентов, типом компонента и типом рендерера. Например, я зарегистрировал средство визуализации и пользовательский компонент, как показано ниже.

faces-config.xml * * 1004

<component>
    <component-type>study.faces.Div</component-type>
    <component-class>javax.faces.component.UIPanel</component-class>
</component>

<render-kit>
    <render-kit-id>HTML_BASIC</render-kit-id>
    <renderer>
        <component-family>javax.faces.Panel</component-family>
        <renderer-type>study.faces.DivRenderer</renderer-type>
        <renderer-class>com.study.ui.DivRenderer</renderer-class>
    </renderer>
</render-kit>

Я также зарегистрировал новый тег в my.taglib.xml файле, как показано ниже:

<tag>
    <tag-name>div</tag-name>
    <component>
        <component-type>study.faces.Div</component-type>
        <renderer-type>study.faces.DivRenderer</renderer-type>
    </component>
</tag>

Эта конфигурация работает очень хорошо. Однако я не понял, почему при регистрации рендерера требуется строка <component-family>javax.faces.Panel</component-family>. В my.taglib.xml компонент и средство визуализации соединены, и, ИМХО, этого должно было быть достаточно для выбора соответствующего средства визуализации для компонента. Какая польза от дополнительного параметра <component-family>?

Я проводил исследования в Google, и все ответы, которые я получил, были такими, как «Один рендер может использоваться для рендеринга нескольких компонентов. Эти компоненты принадлежат одному семейству». Но эти заявления не прояснили мою путаницу. Может ли кто-нибудь объяснить связь между типом компонента, семейством компонентов и стратегией выбора визуализатора? (Надеюсь, с хорошим примером.)

Ответы [ 2 ]

36 голосов
/ 10 ноября 2011

Рендерер выбирается семейством компонентов, а не типом компонента, как вы, вероятно, ожидаете.

Давайте процитируем спецификацию JSF 2.0 :

3.1.2 Тип компонента

Хотя компонент UIComponent не является свойством, он является важной частью данных, связанных с каждым подклассом UIComponent, что позволяет экземпляру Application создавать новые экземпляры UIComponent подклассы с этим типом.См. Раздел 7.1.11 «Фабрики объектов» для получения дополнительной информации о типе компонента.

3.1.3 Семейство компонентов

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

По сути, тип компонента является обязательнымдля JSF для создания компонента методом Application#createComponent().

UIComponent component = context.getApplication().createComponent("study.faces.Div");

Преимущество заключается в том, что компонент study.faces.Div не зависит от времени компиляции и, следовательно, предлагает полиморфизм времени выполненияи возможности подключения (если вы знакомы с механизмом JDBC Class#forName() и его фабриками , то вы лучше поймете эту часть).

Каждый тип компонента принадлежит к семейству, которое можетсостоят из одного или нескольких компонентов.Рендерер выбирается на основе семейства компонентов и типа рендерера: RenderKit#getRenderer()

Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), component.getRendererType());

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

Следующая запись faces-config.xml

<component>
    <component-type>study.faces.Div</component-type>
    <component-class>javax.faces.component.UIPanel</component-class>
</component>

сообщает JSF, что Application должен создавать экземпляр данного класса компонентов всякий раз, когда должен быть создан компонент данного типа компонента.Семейство компонентов там не указано, потому что оно уже неявно известно component.getFamily().

. И следующая faces-config.xml запись

<render-kit>
    <renderer>
        <component-family>javax.faces.Panel</component-family>
        <renderer-type>study.faces.DivRenderer</renderer-type>
        <renderer-class>com.study.ui.DivRenderer</renderer-class>
    </renderer>
</render-kit>

сообщает JSF, что RenderKit должен вернутьсяэкземпляр данного класса визуализатора всякий раз, когда запрашивается визуализатор данного семейства компонентов и типа визуализатора.

Следующая .taglib.xml запись

<tag>
    <tag-name>div</tag-name>
    <component>
        <component-type>study.faces.Div</component-type>
        <renderer-type>study.faces.DivRenderer</renderer-type>
    </component>
</tag>

сообщает JSF (ну, Facelets)что данный тег должен создать компонент данного типа компонента в корне представления (класс которого был определен в faces-config.xml), и что его тип рендерера должен быть установлен на данный тип рендерера.Обратите внимание, что тип компонента не используется для выбора средства визуализации, вместо этого он используется для создания компонента в корне представления.Также обратите внимание, что запись типа рендерера является необязательной.В противном случае будет использоваться собственный предопределенный тип рендерера компонента.Это позволяет повторно использовать существующие типы компонентов с другим типом рендерера.

3 голосов
/ 10 ноября 2011

javadoc говорит о getFamily():

Возвращает идентификатор семейства компонентов, к которому принадлежит этот компонент.Этот идентификатор в сочетании со значением свойства rendererType может использоваться для выбора соответствующего Renderer для этого экземпляра компонента.

Обоснование сопровождающего рассматривается в спецификации JSF :

Семейство компонентов

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

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

...