Просмотр полной версии : Интерфейс и его имплементация
Appleman
13.12.2017, 14:47
Вопрос по книге Сандерса о паттернах проектирования в AS3 (Купил вчера в PDF в прекрасном качестве, весь код можно копипастить, если кому надо книжку, с радостью поделюсь). Авторы пишут о предпочтении "программирования от интерфейса (супертипа), а не его имплементации". В качестве примера приводится то, что в моей программе выглядело бы вот так:
private var hero:Character = new Hero();
разумеется, Hero - наследник Character. Я правильно понимаю, что при таком объявлении во-первых, не будет ошибки компиляции, во-вторых, везде, где параметр типизируется как Character, мой передаваемый туда hero также пройдёт без ошибок, и в-третьих, если где-то будет обращение к свойству другого наследника Character (например Enemy), я сразу получу ошибку в рантайме?
И что вообще уважаемые знатоки думают о таком подходе?
undefined
13.12.2017, 14:58
ты сразу ограничиваешь функционал своего героя суперклассом Character, теряя всю специфику Hero
И что вообще уважаемые знатоки думают о таком подходе?
Такой "подход" называется полиморфизмом - это один из принципов ООП. Изучите сначала его, чтобы не задавать подобные странные вопросы.
Appleman
13.12.2017, 16:10
Такой "подход" называется полиморфизмом - это один из принципов ООП. Изучите сначала его, чтобы не задавать подобные странные вопросы.
Вообще-то я привёл ход рассуждения. Тот полиморфизм, который я знаю (хотя безусловно не претендую на экспертность ни в какой степени, поэтому и спрашиваю), вполне будет "работать" и в такой форме:
public var hero: Hero = new Hero();
при условии, что Hero - наследник Character. Более того, если какой-то метод в Character будет записан как "абстрактный" и переопределён в классе-наследнике Hero, то в соответствии с принципом полиморфизма он будет корректно вызван для экземпляра типа Hero, несмотря на то, что объявлен он не с использованием имени суперкласса. Собственно об этом и вопрос.
если где-то будет обращение к свойству другого наследника Character (например Enemy), я сразу получу ошибку в рантайме?
Ты получишь ошибку компиляции при обращении к свойству Enemy или Hero, без разницы.
Ты объявил переменную как Character. Абсолютно неважно, что ты туда запихаешь в рантайме. Компилятор видит, что ты пытаешься вызвать несуществующий метод именно у Character. Это тип переменной, и он не зависит от того, какой конкретно объект туда записан.
Appleman
13.12.2017, 21:33
Это тип переменной, и он не зависит от того, какой конкретно объект туда записан.
На фига тогда так писать? Или предполагается, что суперкласс полностью абстрактный и не содержит ВООБЩЕ никакой реализации, оставляя всё своим наследникам?
undefined
13.12.2017, 21:43
часто так пишут в сигнатурах методов, а не при объявлении переменных.
public function doSomething(character:Character):void
Я не понимаю этого вопроса.
Ну вот у тебя допустим объявлена переменная типа Спрайт.
Ты можешь туда любую кнопку запихать.
Но если ты в коде обратишься к этой переменной не как к Спрайту, а как к кнопке, то получишь ошибку компиляции? Конечно получишь, потому что у Спрайта нет таких свойств которые ты добавил в кнопку-наследника. Для компилятора это Спрайт! Потому что переменная имеет тип Спрайт. И компилятору не надо дожидаться рантайма чтобы указать тебе на ошибку: ты вызываешь свойства и методы, которых нет у данного типа. Если хочешь обращаться к свойствам и методам кнопки, укажи что это кнопка и проблем не будет. Что тут нелогичного?
Appleman
13.12.2017, 22:02
Как будто это я придумал :)
Вот смотрите из книги по шаблонам проектирования, буквально первая глава:
// Абстрактный класс
public class Polymorphism
{
public function myMusic():void
{
// Резервные детали для подклассов
}
}
public class Rock extends Polymorphism
{
override public function myMusic():void
{
trace(“Play Jimmie”);
}
}
import flash.display.Sprite;
public class PlayMusic extends Sprite
{
var rock:Polymorphism;
var classic:Polymorphism;
var country:Polymorphism;
var jazz:Polymorphism;
public function PlayMusic():void
{
rock=new Rock();
rock.myMusic();
Вот видите, как в самом конце всё собирается вместе?
И? Класс Rock же не создал новый метод, которого нет в Polymorphism. Он переопределил суперметод. В этом и заключается полиморфизм. А вопрос то в чем?)
Переменная rock имеет тип Polymorphism.
У типа Polymorphism есть метод myMusic().
У переменной rock вызывается метод myMusic(), который есть у ее типа.
Где тут компилятору кричать "Караул!"?
Appleman
13.12.2017, 23:32
Всё. Я опять похоже "запоролся". Вся эта конструкция работает при условии, что у наследников нет никакой "отсебятины" и они только переопределяют методы супера. Так?
Ну да, так.
Как только пошла отсебятина — надо приводить к нужному конкретному классу, у которого эта отсебятина.
Добавлено через 18 минут
То есть если ты создашь у класса Rock кастомный метод playDoors(), то не сможешь вызвать его у переменной rock:Polymorphism. Тебе придется кастовать ее к типу Rock, у которого есть этот метод:
(rock as Rock).playDoors();Тогда компиллятор пропустит.
Однако, если в переменной rock на этот момент окажется не экземпляр класса Rock, то будет ошибка уже в runtime, потому что кастинг вернет null, у которого нет метода playDoors(). Поэтому придется всю конструкцию зашить еще и в проверку:
if (rock is Rock) (rock as Rock).playDoors();
caseyryan
14.12.2017, 07:35
Appleman, тебе просто нужно по-больше опыта наработать, чтобы всё понять. Со временем понимание таких штук записывается просто на уровень ДНК)) Когда сразу много информации попадает в голову, она просто превращается в кашу. Пиши игры, приложения, не забрасывай это дело и тогда точно всё поймёшь
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.