Нормально ли иметь элемент ClientBundle в содержащем ClientBundle?

В моем приложении у меня есть MyAppResources, который в основном будет содержать пользовательские стили для приложения. Я думаю о том, что является хорошим способом применить пользовательские стили к стандартным виджетам, таким как CellTable, наряду с пользовательскими стилями макета и пользовательских виджетов?

Мой вопрос: поскольку MyAppResources является одноэлементным (это не обязательно, как упоминалось в других сообщениях), но CellTableResources не является, а CellTableResources является членом этого экземпляра, который также является интерфейсом расширяя ClientBundle, будет ли создаваться прокси CellTableResources для каждого MyAppResources.INSTANCE.cellTableResources().foo()?

Если да, могу ли я создать MyAppResources.CELLTABLE_RESOURCE_INSTANCE, чтобы обойти это? Или создание прокси будет незначительным, даже если будет много обращений к MyAppResources.INSTANCE.cellTableResources().#?

Во-вторых, скорее вопрос для обсуждения: как лучше всего использовать несколько ClientBundle в этом случае? Должен ли я вместо этого использовать CellTableResources отдельно (удалить его из MyAppResources), используя GWT.create(CellTableResources.class); в виджете, который в нем нуждается (или используя синглтон, как у меня для MyAppResources)?

MyAppResources:

public interface MyAppResources extends ClientBundle {
    public static final MyAppResources INSTANCE =  GWT.create(MyAppResources.class);

    @Source("MyAppStyles.css")
    public MyAppCssResource css();

    public CellTableResources cellTableResources();

}

CellTableResources:

public interface CellTableResources extends CellTable.Resources {

    interface CellTableStyle extends CellTable.Style {
    }

    @Override
    @Source({ CellTable.Style.DEFAULT_CSS, "CellTableStyles.css" })
    CellTableStyle cellTableStyle();

    @Source("green_light.png")
    ImageResource getGreenLight();

    //...
}

Спасибо за чтение.


person foamroll    schedule 04.12.2013    source источник
comment
Ваш заголовок спрашивает, подходит ли практика, но затем вопрос в теле вместо этого спрашивает, создается ли новый экземпляр при каждом вызове метода. Если не имеет значения, создается один экземпляр или много (и вы это указываете), то почему вы спрашиваете?   -  person Colin Alworth    schedule 04.12.2013
comment
Я не уверен, действительно ли не имеет значения, создан ли один или несколько экземпляров CellTableResources, и поэтому я спросил, должен ли я оставить его там или нет. Могу ли я предположить, что хотя CellTableResources является интерфейсом, он будет создан один раз для синглтона MyAppResources?   -  person foamroll    schedule 04.12.2013
comment
Я понимаю, что вы говорите, что если содержащий ClientBundle на самом деле является синглтоном из-за использования GWT.create(...), то это не имеет значения и для члена. Однако я не использую GWT.create(...) для члена. Кроме того, каков будет кумулятивный эффект от наличия нескольких таких членов?   -  person foamroll    schedule 04.12.2013
comment
Хорошо, понял - я попытаюсь суммировать плюсы и минусы в реальном ответе...   -  person Colin Alworth    schedule 05.12.2013


Ответы (1)


Вопрос из нескольких частей, поэтому я попытаюсь ответить на него в нескольких частях:

Какова стоимость GWT.create()?

Большая часть класса GWT — это «магия», вещи, которые вы не можете написать для себя другими способами, поскольку они вызывают компилятор для заполнения конкретных деталей за вас. Они часто отличаются при работе в режиме разработки и при компиляции в JS.

В случае с GWT.create получается, что это скомпилировано в new — оно используется только для создания новых экземпляров. Итак, какова стоимость нового экземпляра по сравнению с синглтоном? Это полностью зависит от создаваемого объекта. Если в объекте нет полей, то затраты практически бесплатны — фактически компилятор может фактически удалить вызов конструктора и все равно переписать все последующие методы как static!

Это то, что происходит в большинстве случаев - GWT.create следует считать очень дешевым, если только вы не делаете что-то глупое, например, вызываете его в цикле, который выполняется много раз.

Что происходит, когда я перечисляю метод ClientBundle внутри другого ClientBundle?

Что происходит, когда вы перечисляете что-нибудь внутри ClientBundle?

Все, что может быть указано в ClientBundle, должно быть аннотировано @ResourceGeneratorType, указывающим, как сгенерировать этот тип. Например, вот ImageResource:

/**
 * Provides access to image resources at runtime.
 */
@DefaultExtensions(value = {".png", ".jpg", ".gif", ".bmp"})
@ResourceGeneratorType(ImageResourceGenerator.class)
public interface ImageResource extends ResourcePrototype {
//...

Он призывает ImageResourceGenerator создавать изображения по мере необходимости. Любой класс, описанный в этой аннотации, должен реализовать com.google.gwt.resources.ext.ResourceGenerator, который описывает, как подготовиться к работе, как создать необходимые поля, как их инициализировать и как закончить.

Так как же это выглядит для самого ClientBundle? Обратите внимание на com.google.gwt.resources.rg.BundleResourceGenerator — это очень простой класс, который просто вызывает GWT.create() для типа заданного метода. Итак, предсказуемо, это означает, что эти «дочерние» ClientBundles создаются с помощью GWT.create, более или менее так же, как вы могли бы сделать в противном случае.

Ладно, что это значит в данном конкретном случае?

Оказывается, экземпляры ClientBundles не имеют полей, из которых они отслеживают вновь созданные объекты, а вместо этого имеют статические члены, которые они используют вместо этого — фактически синглтоны. Это означает, что после того, как вы вызвали метод один раз, экземпляр, который он возвращает, будет тем же самым экземпляром, который был создан при следующем вызове. Два разных ClientBundle с одинаковым содержимым, конечно же, сохранят две разные копии объектов, но не имеет значения, сколько раз вы создаете ClientBundle — его внутреннее устройство всегда будет одним и тем же.

Что-нибудь еще?

Ага! Помните, что здесь вы имеете дело с интерфейсами, а не с классами, так что вы можете расширять несколько раз одновременно!

public interface MyAppResources extends 
       ClientBundle, 
       CellTable.Resources, 
       CellTree.Resources {//etc
  //...

Теперь, если два интерфейса описывают одни и те же методы, у вас могут возникнуть проблемы, но если нет, то это может дать преимущество при создании спрайтовых изображений. Каждый отдельный ClientBundle будет использовать свой собственный пул изображений при подготовке их к использованию — если у вас есть ClientBundle внутри ClientBundle, они не будут работать вместе, чтобы спрайтить изображения в более крупные части. Чтобы получить это, вам нужно сделать только один тип ClientBundle. Это может не иметь значения в вашем конкретном случае, но я решил, что об этом также стоит упомянуть.

person Colin Alworth    schedule 04.12.2013
comment
Тщательный ответ; Спасибо! Я действительно задавался вопросом о дальнейшем объединении спрайтовых изображений. Я подумал, что могу переместить их аксессоры в один интерфейс, хотя ваше предложение было бы чище. - person foamroll; 05.12.2013
comment
Большинство маленьких изображений вообще не отображаются спрайтом, поэтому я не обратил на это внимания. В современных браузерах вместо этого используются URL-адреса данных, чтобы избежать даже одного отдельного файла. - person Colin Alworth; 05.12.2013