IArrayExt = interface(IArray)
function GegObject(const AIndex: Integer): ISuperObjectExt;
end;
function TArrayExt.GetObject(const AIndex: Integer): IObjectExt;
var
Obj: IObject;
begin
Obj := Self.GetObj[AIndex]; // метод из IArray
Result := Obj as IObjectExt; // так не работает
end;
Дальше с интерфейсами разбираюсь, как в этом случае вернуть нужный мне интерфейс, точнее привести к нужному типу?
Result := Obj as IObjectExt;
Поставь GUID у интерфейсов или Result := IObjectExt(Obj)
Это стоит, тут для краткости
Тогда реализацию в студию
Так сработало - Result := IObjectExt(Obj)
Так делать не стОит - последующие изменения в реализации могут добавить граблей надежней всего Supports() - покрывает большую долю различных реализаций
Не пойму в чём фишка интерфейсов? Отлаживать сложно, непонятно как будут себя вести в мультипотоке(счётчик ссылок то один), ну и в VCL не наблюдал обилие интерфейсов. Есть ли примивный пример, где все скажут что ДА тут интерфейсы как нигде в тему?
целая куча статей в интернете зачем нужны интерфейсы, проще их почитать чем всю инфу сюда опять вываливать
Странный вопрос. Вы предлагаете на пальцах быстро пояснить инструмент, предназначенный для того, чтоб сложные приложения сделать надежнее?
В моём случае как тогда лучше написать?
Supports - это если GIUD установлен и есть реализация в классе. А приведение вполне возможно, т. к. у него есть наследование интерфейсов, но при рефакторинге могут возникнуть проблемы. Ну и приведение работает значительно быстрее.
1. Уникальный менеджер памяти 2. Автоуничтожение 3. Счетчик ссылок потокбезопасен 4. Есть weak - очистка слабых ссылок 5. Удобно делать реализацию, если код написан на другом языке, поддержиющих интерфейсы 6. Множественное наследование 7. Можно реализовать несколько реализаций одного и того же интерфейса И многое другое.
Почему такой прекрасный инструмент слабо используется и в VCL и в LCL? Вот ООП там сплошь и рядом.
В FMX - прямо многое реализовано на интерфейсах. Но интерфейсы нужно применять для своих задач.
Потому что нет смысла использовать бинокль, когда хочешь почитать книжку, есть более простые инструменты
Ещё одно применение - использовать интерфейсы можно между разными программами и языками
Как понять когда нужен бинокль, а когда очки?
Потому что его нужно применять только там где он необходим. В VCL в нем необходимости нет, у себя же в софте мы используем интерфейсы практически повсеместно в бизнеслогике.
когда/если возникнут задачи, где полезны интерфейсы, ты сам поймешь что они нужны если не юзал - значит не было задач под них. а тянуть их в код лишь бы были, не стоит
Можно тупо на процедурах и функциях реализовать ВСЁ вместо ООП и не понять что ООП там лучше подходит
Например, когда в разных классах нужен определенный одинаковый набор методов, но сделать так, чтоб они были все от одного предка нельзя
ок. если можно - делай :)
вот это очень полезно. на ооп сделать можно, но будет винегрет из кода
ООП позволяет лучше организовать код в большом проекте. Что позволяет его проще масштабировать в будущем
процедуры тоже позволяют переиспользовать код
Это никак не помогает в организации кода, это помогает лишь в его сокращении
Функциональщина без интерфейсов - в паскале, это жесть не работающая
Смотря что за проект, не вездуе нужно интерфейсы тянуть. например у меня в РММ они вообще не используются ибо не нужны
У тебя там реализация на ООП Но я про другое. При функциональщине по идее нужны для работы всякие структуры данных, типа списков и т. д. Вот это все удобно реализовать на интерфейсах, чтобы удобно было пользоваться.
первый раз слышу чтобы типы данных реализовывали на интерфейсах. У нас интерфейсы применяются для имплементации конкретной части бизнеслогики, зачастую вынесеную совсем далеко
Удобно: авторазрушение и все такое.
После того как ввели инлайнвары с скоповой обвязкой - все это стало шататься
Ничего не стало. Все там нормально 😁
Если ты не видишь проблемы - это не значит что её нет
Если ты не используешь инлайн вары, то и волновать тебя не должны скопы
Это только в новых версиях и надо их очень хорошо понимать. Я пока на токио сижу. Но и там тоже можно автоудаление реализовать другими способами. А тема изначально была про функциональщину. К ней нужны структуры для хранения данных, их проще реализовать с нужными фичами через интерфейсы. Так мне кажется.
я не использую, коллеги пытаются, но вот этот код, ранее работавший совершенно нормально, теперь посыпался и его использовать нельзя https://alexander-bagel.blogspot.com/2014/11/store.html
шаредптры который
разделение кода - это самая полезная часть интерфейсов
AutoDestroy?
Статья хорошая. Но начиная с TestWriteBySharedPtr так делать не рекомендует Microsoft, т. к. закрытие handles должно происходить в ручном режиме и для этого необходимо использовать IDisposable Типа что-то такого https://learn.microsoft.com/ru-ru/dotnet/api/system.idisposable?view=net-8.0
Да ей 100 лет в обед, третья часть статьи устарела давно и осталась просто для истории :)
В общем приведение типов работает, но приведённый интерфейс не знает методов интерфейса *Ext (а при попытке использования Supports - я не получаю интерфейс, что ожидаемо, т.к. дочерний интерфейс не реализует медотов родителя). И в этом случае методы интерфейса *Ext не работают, а это единственное, для чего я это создавал, когда спросил, как написать хелперы для интерфейса. Обходной манёвр сделал - выдирание всех данных из дочернего и создание нового родительского. Это это как-то перебор, хотя и работает
Возможно и заблудился, не спорю, вот пример: type IMyInt = interface ['{85FEDDA8-4248-4B21-8FB5-0D5A29C67AF1}'] function GetStr: string; end; TMyInt = class(TInterfacedObject, IMyInt) function GetStr: string; end; IMyInt2 = interface ['{0E925C39-27B7-4D70-9A38-720D1D22DEBD}'] function GetObj: IMyInt; end; TMyInt2 = class(TInterfacedObject, IMyInt2) function GetObj: IMyInt; end; { TMyInt } function TMyInt.GetStr: string; begin Result := 'True'; end; { TMyInt2 } function TMyInt2.GetObj: IMyInt; begin Result := TMyInt.Create; end; type IMyIntExt = interface(IMyInt) ['{B28EFFE4-36A0-43A1-87D5-C4ADB0EFA059}'] function GS: string; end; TMyIntExt = class(TMyInt, IMyIntExt) function GS: string; end; IMyIntExt2 = interface(IMyInt2) ['{62FBE49D-ED7B-4EB6-BC2B-9B7DBFD01895}'] function GO: IMyIntExt; end; TMyIntExt2 = class(TMyInt2, IMyIntExt2) function GO: IMyIntExt; end; { TMyIntExt } function TMyIntExt.GS: string; begin Result := Self.GetStr; end; { TMyIntExt2 } function TMyIntExt2.GO: IMyIntExt; begin Result := IMyIntExt(Self.GetObj); end; function MI: IMyInt2; begin Result := TMyInt2.Create; end; function MIExt: IMyIntExt2; begin Result := TMyIntExt2.Create; end; var SS := MI.GetObj.GetStr; var SS2 := MIExt.GO.GS; Результат: SS='True', SS2 дома эксепшн получаю Всё, что мне нужно, это чтобы SS2 получилось заполнить используя хелперы GO и GS
чатик мне посоветовал так поменять: type IMyInt = interface ['{85FEDDA8-4248-4B21-8FB5-0D5A29C67AF1}'] function GetStr: string; end; TMyInt = class(TInterfacedObject, IMyInt) function GetStr: string; end; IMyIntExt = interface(IMyInt) ['{B28EFFE4-36A0-43A1-87D5-C4ADB0EFA059}'] function GS: string; end; TMyIntExt = class(TMyInt, IMyIntExt) function GS: string; end; IMyInt2 = interface ['{0E925C39-27B7-4D70-9A38-720D1D22DEBD}'] function GetObj: IMyIntExt; end; TMyInt2 = class(TInterfacedObject, IMyInt2) function GetObj: IMyIntExt; end; IMyIntExt2 = interface(IMyInt2) ['{62FBE49D-ED7B-4EB6-BC2B-9B7DBFD01895}'] function GO: IMyIntExt; end; TMyIntExt2 = class(TMyInt2, IMyIntExt2) function GO: IMyIntExt; end; implementation { TMyInt } function TMyInt.GetStr: string; begin Result := 'True'; end; { TMyInt2 } function TMyInt2.GetObj: IMyIntExt; begin Result := TMyIntExt.Create; end; { TMyIntExt } function TMyIntExt.GS: string; begin Result := Self.GetStr; end; { TMyIntExt2 } function TMyIntExt2.GO: IMyIntExt; begin Result := Self.GetObj; end; function MI: IMyInt2; begin Result := TMyInt2.Create; end; function MIExt: IMyIntExt2; begin Result := TMyIntExt2.Create; end; procedure TForm15.Button1Click(Sender: TObject); begin var SS := MI.GetObj.GetStr; var SS2 := MIExt.GO.GS; end;
Ну так и я смог бы, но всё, что не *Ext - это не моё, трогать нельзя
ГПТ мне посоветовало хелпер для интерфейса написать, а Delphi его не приняла, почитал - он не реализован
TMyIntExt2.GO должен возвратить новый объект: Result := TMyIntExt.Create
Там на самом деле данные заполняются и парсятся при вызове первоначальной функции MIExt. Но сейчас я так и делаю, вызываю в TMyInt2.GO дочерний метод TMyInt.GetObj, получаю из него данные, заново загоняю их на парсинг уже в TMyIntExt.Create. Но это получается двойная работа и потеря производительности
Обсуждают сегодня