PDA

Просмотр полной версии : Паттерны Объединение методов с одинаковой реализацией


djken
28.03.2019, 04:34
Все привет. Подскажите пожалуйста, как правильней переделать? Никогда не связывался с Интерфейсами. Хотя в моем случае понимаю не совсем даже интерфейсы нужны.

В приложении есть разные окна, которые могут сменять друг друга (одновременно существовать не может несколько окон). Например, окно с приветствием - класс WelcomeScreen, настройками - класс SettingsScreen, информацией о профиле - AccountScreen и т.д.
Сейчас в каждом из них есть методы:

show() // плавно показать окно
hide() // плавно скрыть окно
changeLang(lang:String) // сменить язык
resize() // ресайз объектов в окне
destroy() // ликвидировать


Реализация show() и hide() одинакова во всех окнах - следовательно их можно вынести в некий общий класс. Реализация остальных методов различается для разных окон.

Как понимаю, можно создать интерфейс, например IWindow - в котором будут перечислены все эти методы.
И создать некий шаблонный класс Window, который будет имплементить все эти методы - show() и hide() с реализацией. А остальные методы оставить пустыми - классы наследники будут делать override.


package
{
public interface IWindow
{
function show():void;
function hide():void;
function resize():void;
function changeLang():void;
function destroy():void;
}
}

package
{
import com.greensock.TweenMax;
import com.greensock.easing.Linear;
import flash.display.MovieClip;
import flash.events.Event;

public class Window extends MovieClip implements IWindow
{
public static const HIDE_COMPLETE:String = 'hideComplete';

public function show():void
{
TweenMax.to(this, 0.3, {alpha: 1, ease:Linear.easeNone});
}

public function hide():void
{
TweenMax.to(this, 0.5, {alpha: 0, ease:Linear.easeNone, onComplete:onHideTweenFinished});
}

private function onHideTweenFinished():void
{
dispatchEvent(new Event(HIDE_COMPLETE));
}

public function changeLang():void {}

public function resize():void {}

public function destroy():void {}
}
}


Теперь можно создавать любое окно наследуясь от Window public class SettingsScreen extends Window. Но мне эта реализация не совсем нравится. Я единственный разработчик в приложении - и поэтому знаю/помню что в каждом окне мне нужно делать override пустых методов. А если, допустим, за приложение взялся еще кто-нибудь дорабатывать, хочет добавить новое окно - он вряд ли поймет, что ему нужно перезаписывать эти методы.

Как все таки правильней будет?

Либо же вариант 2. В классе Window описать только классы с реализацией - show() и hide(). В интерфейсе IWindow обозначить остальные методы (они будут реализовываться в каждом окне по-своему). И создать некий класс WindowManager, в котором будет метод добавления окна addWindow(win:IWindow) - этот класс будет руководить парадом появления/скрытия окон.
И в итоге каждое отдельное окно должно будет наследоваться от Window. А чтобы мог добавляться в WindowManager - должен имплементить IWindow.

Или так лучше?

Заранее спасибо за помощь в вопросе!

Wolsh
28.03.2019, 09:08
вариант 3 — методы show() и hide() реализованы в менеджере окон.

Appleman
28.03.2019, 10:03
djken, а что мешает унаследовать все эти окна от одного базового класса, и прописать там эти методы как абстрактные? В этом случае и ты, и сторонний разработчик не сможете уклониться от реализации всех методов в наследниках.

Bletraut
28.03.2019, 11:10
djken, а что мешает унаследовать все эти окна от одного базового класса, и прописать там эти методы как абстрактные? В этом случае и ты, и сторонний разработчик не сможете уклониться от реализации всех методов в наследниках.

Разве во флеше есть абстрактные методы?

Appleman
28.03.2019, 14:42
Разве во флеше есть абстрактные методы?

public function someAbstractMethod() : void
{
throw ("Это абстрактный класс, должен быть реализован в наследниках!");
}

djken
28.03.2019, 14:51
Wolsh, да, в принципе в моем случае можно так сделать. Но что, если за появление/скрытие должно отвечать само окно? (сначала внтури каждого окна всплывает логотип как-то особенно, потом остальные элементы) - в этом случае WindowManager не обязан знать ничего о внутреннем поведении окна при открытии/закрытии, и следовательно, мне нужно реализовать эти методы внутри класса Window - как в этой ситуации?

Appleman в AS3 нет Абстрактных классов и методов. Если только не реализовать их самом по такому принципу, например https://joshblog.net/2007/08/19/enforcing-abstract-classes-at-runtime-in-actionscript-3/

caseyryan
28.03.2019, 15:04
метод changeLang(lang:String) вообще лучше не на уровне окна делать. Я бы лучше сделал наследники или даже обертки для TextField и там слушал событие смены языка, и после события менял текст в них. Независимо от окон вообще.

Метод resize реализовать одинаково для всех окон, в базовом классе. Остальное пофиг.
Если все-таки нужно чтобы при вызове что-то предупреждало разработчика о том, что метод по-любому надо перезаписать, то Appleman предложил хороший вариант. Реальной абстракции в ас3 все равно нет и компилятор не пожалуется на отсутствие оверрайда

Bletraut
29.03.2019, 17:55
public function someAbstractMethod() : void
{
throw ("Это абстрактный класс, должен быть реализован в наследниках!");
}

Это костыль какой-то.

caseyryan
29.03.2019, 21:39
Это костыль какой-то.
За неимением лучшего, пойдет. Много раз встречал такое в as3

dimarik
30.03.2019, 00:13
вариант 3 — методы show() и hide() реализованы в менеджере окон.

Полностью согласен

Appleman
31.03.2019, 15:20
Это костыль какой-то.

Вам шашечки или ехать?

На мой взгляд, ни фига не костыль, а вполне себе системное решение. У меня, конечно, опыта немного - всего пара лет самостоятельного изучения, но я не могу представить себе ситуацию обхода подобной конструкции. В моём представлении, функционально работает в точности как абстрактный класс. Или я не прав?

Bletraut
01.04.2019, 18:02
В моём представлении, функционально работает в точности как абстрактный класс. Или я не прав?

За исключением того, что от абстрактных классов нельзя создавать экземпляры и абстракция подразумевает обязательного наследника. А здесь можно и экземпляр создать и метод вызвать.

Хотя ничего не мешает этот throw и в конструктор поместить, но тогда у абстрактного суперкласса не будет реализации конструктора.

caseyryan
01.04.2019, 20:34
Вам шашечки или ехать?

На мой взгляд, ни фига не костыль, а вполне себе системное решение. У меня, конечно, опыта немного - всего пара лет самостоятельного изучения, но я не могу представить себе ситуацию обхода подобной конструкции. В моём представлении, функционально работает в точности как абстрактный класс. Или я не прав?
Если не вызывать метод, то ничего не произойдет. Другой вариант, вызов метода внутри try / catch блока, без вывода стек трейса.

Appleman
01.04.2019, 20:41
Bletraut, caseyryan, да, сорри. Я имел в виду "абстрактный метод", а не "абстрактный класс". Оговорился.

RedHead90
02.04.2019, 19:11
Тоже такое когда-то использовал, но от ощущения костыльности решения при этом избавиться не получалось. Как-то видел, как один кулхацкер таким макаром абстрактные классы делал, кидая в конструкторе исключение, а в наследниках писал

if (false) {
super();
}