Часто я нахожу себя создающим визуальные компоненты, похожие по структуре и структуре. К сожалению, в отличие от свойств и методов, разметка — это сложная вещь для обмена между компонентами через традиционное объектно-ориентированное наследование.
Код макета (MXML) неизбежно дублируется в вашем приложении. Результатом является кошмар обслуживания и множество избыточного кода MXML. Обратите внимание на избыточный MXML, найденный в классах ReportEditor и ListEditor
этого приложения .
Эта статья,
вдохновленная моим коллегой
Крисом Хейеном , будет демонстрировать повторное использование кода как через наследование (свойства и методы), так и через композицию (макет), не прибегая к нежелательному использованию ActionScript для кода макета.
Композиция по наследству
В этом примере приложения у меня есть два редактора: редактор отчетов и редактор списков. Каждый разделяет общий макет, поэтому я извлеку макет в свой собственный класс — EditorLayout.
EditorLayout, написанный на MXML, будет определять макет каждого редактора. Вот мой первый проход в EditorLayout.
<!--EditorLayout.mxml-->
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%">
<fx:Script>
<![CDATA[
[Bindable]
public var title:String;
]]>
</fx:Script>
<mx:HBox width="100%"
backgroundColor="#ededed"
height="30"
verticalAlign="middle"
paddingRight="10"
paddingLeft="10"
borderStyle="solid"
borderColor="#aab3b3">
<mx:HBox id="toolBarChildrenContainer"/>
<mx:Spacer width="100%"/>
<mx:Label id="titleLabel"
color="#333333"
fontWeight="bold"
text="{title}"/>
</mx:HBox>
<mx:VBox id="editorChildrenContainer"
width="100%"
height="100%"
minWidth="0"
minHeight="0"/>
</mx:VBox>
Примечание. По возможности я всегда использую MXML для определения макета. MXML для макета. ActionScript для бизнес-логики.
Хотя каждый редактор будет иметь одинаковую разметку, их содержимое будет отличаться. Для поддержки пользовательского содержимого я добавлю несколько открытых свойств, чтобы разрешить внедрение содержимого в макет. Мне также нужна пара методов, отвечающих за рендеринг этого контента. Вот мой второй проход в EditorLayout.
<!--EditorLayout.mxml-->
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%"
initialize="onInitialize(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
public var title:String;
private var _toolBarChildren:Array;
private var _editorChildren:Array;
public function get toolBarChildren():Array
{
return _toolBarChildren;
}
public function set toolBarChildren(value:Array):void
{
_toolBarChildren = value;
}
public function get editorChildren():Array
{
return _editorChildren;
}
public function set editorChildren(value:Array):void
{
_editorChildren = value;
}
protected function onInitialize(event:FlexEvent):void
{
createToolBarChildren();
createEditorChildren();
}
protected function createToolBarChildren():void
{
for each (var toolBarChild:DisplayObject in _toolBarChildren)
{
if (!toolBarChildrenContainer.contains(toolBarChild))
{
toolBarChildrenContainer.addChild(toolBarChild);
}
}
}
protected function createEditorChildren():void
{
for each (var editorChild:DisplayObject in _editorChildren)
{
if (!editorChildrenContainer.contains(editorChild))
{
editorChildrenContainer.addChild(editorChild);
}
}
}
]]>
</fx:Script>
<mx:HBox width="100%"
backgroundColor="#ededed"
height="30"
verticalAlign="middle"
paddingRight="10"
paddingLeft="10"
borderStyle="solid"
borderColor="#aab3b3">
<mx:HBox id="toolBarChildrenContainer"/>
<mx:Spacer width="100%"/>
<mx:Label id="titleLabel"
color="#333333"
fontWeight="bold"
text="{title}"/>
</mx:HBox>
<mx:VBox id="editorChildrenContainer"
width="100%"
height="100%"
minWidth="0"
minHeight="0"/>
</mx:VBox>
Мои редакторы также будут использовать некоторые свойства и методы, поэтому я создам базовый класс для использования традиционного объектно-ориентированного наследования.
<!--Editor.mxml-->
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="comps.*"
title="{editorType} Editor"
width="500"
paddingTop="10"
paddingBottom="10"
paddingLeft="10"
paddingRight="10">
<fx:Script>
<![CDATA[
public static const REPORT:String = "Report";
public static const LIST:String = "List";
[Bindable]
public var editorType:String;
protected function save():void
{
throw new Error("Abstract Class - override this method in a subclass.");
}
]]>
</fx:Script>
</mx:Panel>
Наконец, я создам свои классы редактора. Класс редактора расширит базовый класс Editor и будет состоять из экземпляра EditorLayout. Пользовательское содержимое вводится в общий макет декларативно с использованием MXML.
<!--ReportEditor.mxml-->
<?xml version="1.0" encoding="utf-8"?>
<comps:Editor xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="comps.*"
preinitialize="onPreinitialize(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function saveButton_clickHandler(event:MouseEvent):void
{
save();
}
protected function publishButton_clickHandler(event:MouseEvent):void
{
publish();
}
override protected function save():void
{
//save
}
protected function publish():void
{
//publish
}
protected function onPreinitialize(event:FlexEvent):void
{
editorType = Editor.REPORT;
}
]]>
</fx:Script>
<comps:EditorLayout title="{editorType}">
<comps:toolBarChildren>
<s:Button id="saveButton"
label="Save"
click="saveButton_clickHandler(event)"/>
<s:Button id="publishButton"
label="Publish"
click="publishButton_clickHandler(event)"/>
</comps:toolBarChildren>
<comps:editorChildren>
<comps:ReportForm id="reportForm"/>
</comps:editorChildren>
</comps:EditorLayout>
</comps:Editor>
<!--ListEditor-->
<?xml version="1.0" encoding="utf-8"?>
<comps:Editor xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="comps.*"
preinitialize="onPreinitialize(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function saveButton_clickHandler(event:MouseEvent):void
{
save();
}
protected function submitButton_clickHandler(event:MouseEvent):void
{
submit();
}
override protected function save():void
{
//save
}
protected function submit():void
{
//submit
}
protected function onPreinitialize(event:FlexEvent):void
{
editorType = Editor.LIST;
}
]]>
</fx:Script>
<comps:EditorLayout title="{editorType}">
<comps:toolBarChildren>
<s:Button id="saveButton"
label="Save"
click="saveButton_clickHandler(event)"/>
<s:Button id="submitButton"
label="Submit"
click="submitButton_clickHandler(event)"/>
</comps:toolBarChildren>
<comps:editorChildren>
<comps:ListForm id="listForm"/>
</comps:editorChildren>
</comps:EditorLayout>
</comps:Editor>
Конечный результат (см. Ниже) — более чистый код во всем приложении (без кода макета ActionScript и избыточного кода MXML).
Просмотр включена
Конечно, лучше метод предполагает использование скиннинга архитектуры Flex 4 в. Оставайтесь в курсе.
Обновление: см. Запись в блоге под названием «
Flex Skinning для общего использования ».