ООП Правильное использование интерфейсов в AS3 - PullRequest
2 голосов
/ 31 августа 2011

Я разрабатываю фреймворк, и в процессе работы я столкнулся с интересной, но, скорее всего, основной проблемой. У меня есть базовый класс с именем CoreEngine и два других класса, расширяющих его: CoreEngine1 и CoreEngine2 . Я создал интерфейс, который будет реализован каждым из этих классов для повышения гибкости моего проекта. Однако у меня есть проблема ... Определение моих методов в интерфейсе не соответствует определению в каждом унаследованном классе! Каждый класс должен реализовывать следующий метод:

функция get avatar (): AvatarBase;

Проблема в том, что CoreEngine1 и CoreEngine2 ожидают другой тип аватара:

CoreEngine1

функция get avatar (): AvatarScaling

CoreEngine2

функция get avatar (): AvatarPlatform

Как видите, тип возврата для avatar в CoreEngine1 и CoreEngine2 НЕ соответствует типу, указанному в интерфейсе. Я надеялся, что поскольку AvatarScaling и AvatarPlatform наследуют AvatarBase , у меня не возникнет проблем при компиляции. Однако, это не так. Согласно документации Adobe, типы ДОЛЖНЫ соответствовать интерфейсу. Я пытаюсь следовать одной из основных концепций объектно-ориентированного программирования, чтобы расширить гибкость моей среды: «Программируйте на интерфейс, а не на реализацию». Первое, что приходит мне в голову, это то, что тип возвращаемого значения метода доступа должен иметь тип интерфейса (возможно, я просто ответил на свой вопрос).

Я уверен, что это обычная проблема, с которой другие сталкивались раньше. С архитектурной точки зрения, что вы думаете, это лучший способ решить эту проблему? Заранее спасибо!

С уважением,

Будет

Ответы [ 3 ]

1 голос
/ 31 августа 2011

Это ограничение того, как интерфейсы работают и объявляются.

Если есть наследование, которое может произойти с возвращаемыми типами, как вы описали с AvatarBase и подклассами, то я думаю, что правильный подходсделать тип возвращаемого значения наименьшим общим знаменателем и просто обработать полученный объект на другом конце.Итак, если вы имеете дело с CoreEngine1 объектом, вы знаете, что можете привести результат с AvatarBase до AvatarScaling.Кроме того, если вы не знаете тип объекта, для которого вызываете get avatar(), вы можете проверить возвращаемое значение.Проверка типа тогда потребуется, только если вы хотите вызвать метод, который существует в AvatarScaling, но не в AvatarBase.Я не думаю, что возвращение типа интерфейса принесет вам большую выгоду в этом случае, потому что единственное, что может реализовать интерфейс, это вещи, которые разделяют все формы Аватара, которые не будут отличаться от методов в AvatarBase.

1 голос
/ 31 августа 2011

Как упоминали HotN и Dinko, было бы лучше разрешить get avatar() всегда возвращать AvatarBase и затем приводить возвращаемый объект в качестве конкретного подкласса.

Используя пример Динко:

public /* abstract */ class CoreEngine
{ 
   public /* abstract */ function get avatar():AvatarBase {}
}

public function CoreEngine1 extends CoreEngine
{
   override public function get avatar():AvatarBase { return new AvatarScaling(); }
}

public function CoreEngine2 extends CoreEngine
{
   override public function get avatar():AvatarBase { return new AvatarPlatform(); }
}

public /* abstract */ class AvatarBase {}

public class AvatarScaling extends AvatarBase 
{ 
   public function someAvatarScalingMethod():void {}
}

public class AvatarPlatform extends AvatarBase 
{ 
   public function someAvatarPlatformMethod():void {}
}

Чтобы использовать метод из AvatarScaling, приведите возвращенный объект:

var c1:CoreEngine1 = new CoreEngine1();
var avatarScaling:AvatarScaling = AvatarScaling(c1.avatar());
avatarScaling.someAvatarScalingMethod();

НТН

0 голосов
/ 31 августа 2011

Я думаю, что вы ответили на свой вопрос ... тип возвращаемого значения все равно будет AvatarBase, вам нужно следовать подписи, указанной вами в интерфейсе ... но вы можете технически вернуть ЛЮБОЙ потомок AvatarBase в этой функции.Так что делать что-то вроде

return new AvatarScaling();

в CoreEngine1 было бы вполне приемлемо.

Конечно, в своей вызывающей функции вы получите обратно экземпляр AvatarBase, и вам нужно будет знать, что это такое, чтобы привести к определенному подклассу.

CoreEngine1 ce1 = new CoreEngine1();
AvatarScaling avatar = ce1.avatar() as AvatarScaling; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...