Часто я нахожу себя создающим визуальные компоненты, похожие по структуре и структуре. К сожалению, в отличие от свойств и методов, разметка — это сложная вещь для обмена между компонентами через традиционное объектно-ориентированное наследование.
Код макета (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 для общего использования ».