Pull to refresh

Comments 30

А не лучше ли использовать для «Может двигаться» примеси? «Moveable», «Draggable», «Droppable», etc.
Я сам не флешер, а Джаваскриптер, но языки похожие. В фреймворке LibCanvas есть такая штука, как поведение. Например, Moveable, Draggable, Droppable и достаточно примешать поведение, как объект приобретает соответсвующее свойство. Примешали draggable — его можно двигать мышкой, linkable — можно к нему прикреплять другие элементы и тому подобное. К примеру, какая-то кнопка может выглядеть так:
Button = atom.Class({
  Implements: [Drawable, Clickable, Draggable],
  draw: function () {
    // drawing
  }
});

Теперь она отрисовывается, кликается и тягается.
Это почти одно и то же. При явной композиции нет проблем со случайным перекрытием методов/свойств и с пониманием, откуда что взялось. Но больше писанины.
Логика — великая вещь.
Ошибка с ДвигающиймсПредметом в том, что если сделали уже разделение на Двигающийся и Предмет, то, значит, предметы не двигаются. Иначе не надо было вводить два разных класса — по этим признакам.

Декомпозиция это, знаете ли, сродни поэзии. Все пишут как им прийдет в голову, у ряда людей даже работает, хотя и совершенно по-разному. Парадигм в программировании (http://en.wikipedia.org/wiki/Programming_paradigm) много, и становится со временем все больше.

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

Но суть даже не совсем в этом. В этом специально упрощенном примере показана проблема с сущностью, которая одновременно обладает свойствами нескольких логически обоснованых веток иерархии.
это в ответ на предыдущий комментарий, извиняюсь за путаницу
Бегло посмотрел уроки по pushbutton. Большим минусом данного фреймворка является то, что там слишком часто используются строковые идентификаторы. Стоит в одном месте описаться и работать будет не так как хочешь, но скомпилится все наура. А потом ищи эту «описку».
А разве не выбросится эксепшн «Неизвестный строковый аргумент»?
Может и выбросится, не знаю. Но все-равно было приятней отслеживать такие ошибки на этапе компиляции.
Logger бросит ворнинг в таком случае
Хочу еще добавить, что для этих строковых идентификаторов не будет работать автокомплит, и придется вспоминать: как же я назвал ту сущность?
Я довольно долго сидел на mvc фреймворке PureMVC. Там тоже используются строковые идентификаторы. Чтобы не путаться приходилось использовать строковые константы. Это решает проблему и с автокомплитом и с компиляцией, но все-равно напрягает.
Сейчас сижу на RobotLegs. Хотя мне их механизм инъекций не очень нравится. PureMVC'ый фасад (когда сам забираешь, что тебе нужно) мне больше нравится. Планирую свой велосипед сделать: из RobotLegs взять механизм событий, а из PureMVC глобальный фасад.
антипаттерн называется 'string typing'
Полностью согласен. Именно поэтому отказался от работы с PushButtonEngine, когда понял, что многое там «завязано» на строковых идентификаторах.

Как вариант решения проблемы — создавать классы для хранения статических констант с именами нужных объектов.
UFO just landed and posted this here
но от такого константами не избавиться:
render.rotationProperty = new PropertyReference("@Spatial.rotation");
Я понимаю, что таких констант нужно будет создавать очень много и, на мой взгляд, это как бы не очень хорошо вообще, в принципе, что весь фреймворк держится на строковых идентификаторов, но что мешает строку "@Spatial.rotation" присвоить константе SPATIAL_ROTATION?
Ну тут просто большого выигрыша не будет. Константы помогают, когда конкретная строка (например, идентификатор) встречается много раз в проекте. Здесь же "@Spatial.rotation" будет употребляться от-силы 1-2 раза. Следовательно проще, где нужно, прописать строкой.
Можно конечно извратиться и сделать: "@" + SPATIAL + "." + ROTATION. Ну или немного украсить и обернуть это в утилитную функцию:
public static function getPropertyString(entityName:String, propertyName:String):String
{
return "@" + entityName + "." + propertyName;
}


тогда и с автокомплитом проблем не будет.
как бы вы на питоне писали, не представляю
невероятно, но все вызовы там разрешаются динамически
Терминология авторов фреймворка немного удивляет, потому что у этого уже есть несколько названий: aspect, trait, mixin. А слово компонент (которое вообще значит всё, что угодно) только создаёт путаницу.
Хотя нет, я туплю.
На самом деле для этой конкретной реализации «компонент» вполне ничего, потому что это явная аггрегация.
Изначально нельзя делать однотипными свойствами «красный» и «мотыга», если вы понимаете о чем я.
Сущность следовало бы сразу делить тогда на (двигающийся-статичный).
Не про PushButton, но по теме. На случай, если кому пригодится.
На текущий момент в своём фреймворке я пришёл к такой «композиции»:

class DisplayObject
{
	function compose(c:Function):Object
	{
		var target:IComposer = new c;
		target.host = this;
		return target;
	}
	
	// Указываем для класса любое количество объектов составного функционала.
	// Объект составного функционала заключает в себя все необходимые св-ва
	// и методы для управления этим функционалом.
	// Связь объекта составного функционала с "носителем" осуществляется через св-во "host".
	// Благодаря геттеру, экономим память для объектов, не использующих составной функционал.
	
	private var __listeners:Listeners;
	public function get listeners():Listeners
	{
		return this.__listeners = this.__listeners || this.compose(Listeners);
	}
	
	...
	
	private var __interaction:Interaction;
	public function get interaction():Interaction
	{
		return this.__interaction = this.__interaction || this.compose(Interaction);
	}
	
	...

	private var __drag:Drag;
	public function get drag():Drag
	{
		return this.__drag = this.__drag || this.compose(Drag);
	}
	
	...
	
	// И т.д.
	
	// Пример метода для понимания обратной связи
	public function applyState():void
	{
		if (this.__interaction && this.__interaction.highlight)
		// что-то делаем
	}
}

class Interaction implements IComposer
{
	// Носитель может имплементить нужный интерфейс для обращения к нему напрямую.
	public var host:*;
	
	// Примеры методов (геттеры и подробности реализации опущены):
	
	public function set focus(value:Boolean):void
	{
		Focus.instance.current = this.host;
		this.host.applyState();
	}

	...

	public function set highlight(value:Boolean):void
	{
		this.__highlight = value;
		this.host.applyState();
	}
	
	// И т.д.
}

// Применение

myClip.listeners.add(DragEvent.START, ...);
myClip.interaction.active = true;
myClip.drag.start();

// И т.д


Таким образом, закладываем допустимый составной функционал на уровне определения класса (бонусом получаем работающий автокомплит), соблюдаем инкапсуляцию составного функционала и защищаемся от конфликтов, возможных в mixin`ах.

UFO just landed and posted this here
наследование — это лишь один из инструментов в руках архитектора.
На практике не всегда можно описать бизнес-логику стройной и непротиворечивой иерархией.
В геймдеве это случается довольно часто, поэтому и предложено использовать в числе прочих компонентный подход, и фреймворк стимулирует и упрощает это
UFO just landed and posted this here
Код становится тяжело отлаживать, модифицировать и сопровождать.
Давайте на жабаскрипте писать, зачем вам флеш тогда:) /*troll mode off*/

Я бы за такие примеры по рукам надавал.

А так то да, просто набор инструментов, как хочь так и пользуйся. Меня мвц и наследование вполне устраивает, только моск иногда надо включать когда архитектура рисуется.
В любом случае за ссылочки спасибо, почитаем.
Sign up to leave a comment.

Articles