Заметки о тестировании, программировании и прочий "поток сознания", который жалко писать "в стол"
воскресенье, 28 декабря 2014 г.
суббота, 27 декабря 2014 г.
среда, 24 декабря 2014 г.
Коротко. "О языках"
По мотивам - Objective-C и Delphi
Несмотря на то, что "мне всё равно на чём программировать", скажу - на данный момент Objective-C++ - "мой кумир".
Почему?
Потому, что он сочетает наиболее удачные вещи из "всех известных мне языков программирования".
Итак.
Об удачном.
От С++:
1. Объекты на стеке и как следствие - RAII.
2. Переопределение операторов.
3. Возможность использования STL.
4. Большое количество стандартных и открытых библиотек.
5. Лямбды.
6. Множественное наследование и как следствие - примеси.
7. Итераторы в стиле for (auto Element : Container).
8. Строгая типизация.
9. Шаблоны.
От Objective-C:
1. Подсчёт ссылок.
2. "Встроенная" сериализация.
3. NSProxy.
4. Мета-классы.
5. Протоколы.
6. Общий базовый предок для всех объектов.
7. NSOperation.
8. Категории.
9. try..finally.
10. NSDictionary.
11. Блоки (аналоги лямбд).
12. Duck-typing (оно же правда и минус).
13. Итераторы в стиле for (ElementType Element in Container).
14. Одиночное наследование и как следствие - "отсутствие бардака".
На стыке технологий:
1. Возможность положить объект C++ в объект Objective-C и как следствие - Holder'ы.
2. Возможность положить объект Objective-C в объект C++ и как следствие - Var'ы и динамические фабрики.
В итоге - C++ и Objective-C - это принципиально РАЗНЫЕ языки, со своими плюсами и минусами, а вот Objective-C++ это их удачная комбинация позволяющая комбинировать как плюсы, так и минусы.
Ну можно конечно "скомбинировать ОДНИ минусы" :-) Но тут уж как говориться - "каждый сам себе злобный буратина" :-)
Несмотря на то, что "мне всё равно на чём программировать", скажу - на данный момент Objective-C++ - "мой кумир".
Почему?
Потому, что он сочетает наиболее удачные вещи из "всех известных мне языков программирования".
Итак.
Об удачном.
От С++:
1. Объекты на стеке и как следствие - RAII.
2. Переопределение операторов.
3. Возможность использования STL.
4. Большое количество стандартных и открытых библиотек.
5. Лямбды.
6. Множественное наследование и как следствие - примеси.
7. Итераторы в стиле for (auto Element : Container).
8. Строгая типизация.
9. Шаблоны.
От Objective-C:
1. Подсчёт ссылок.
2. "Встроенная" сериализация.
3. NSProxy.
4. Мета-классы.
5. Протоколы.
6. Общий базовый предок для всех объектов.
7. NSOperation.
8. Категории.
9. try..finally.
10. NSDictionary.
11. Блоки (аналоги лямбд).
12. Duck-typing (оно же правда и минус).
13. Итераторы в стиле for (ElementType Element in Container).
14. Одиночное наследование и как следствие - "отсутствие бардака".
На стыке технологий:
1. Возможность положить объект C++ в объект Objective-C и как следствие - Holder'ы.
2. Возможность положить объект Objective-C в объект C++ и как следствие - Var'ы и динамические фабрики.
В итоге - C++ и Objective-C - это принципиально РАЗНЫЕ языки, со своими плюсами и минусами, а вот Objective-C++ это их удачная комбинация позволяющая комбинировать как плюсы, так и минусы.
Ну можно конечно "скомбинировать ОДНИ минусы" :-) Но тут уж как говориться - "каждый сам себе злобный буратина" :-)
Коротко. "Ни о чём". Какие "практики" я использую при написании кода
"практики" - какое заумное слово..
но...
что я использую
1. Наследование
2. Виртуальные функции
3. Лямбды (когда виртуальностью не обойдёшься)
4. Шаблон Publisher/Subscriber.
5. Параметризованные контейнеры (Generic'и или stl).
6. Интерфейсы.
7. Примеси (когда другим не обойдёшься)
8. Понимание того, что бизнес-логика НЕ ДОЛЖНА зависеть от GUI
по большому счёту- ВСЁ
никакой "высшей математики"
не..ну ещё...
9. Шаблон Декоратор
Это я к чему?
Просто к тому, что я тут пытался человека убедить, что "мой код простой как пробка".
Это код "ремесленника", который "знает три аккорда" и "лабает на них".
никакой "высшей математики"...
И да! Это не "повод для гордости".
Просто - делюсь.
Ну и:
10. Тесты. Просто тесты. "Всегда и везде".
но...
что я использую
1. Наследование
2. Виртуальные функции
3. Лямбды (когда виртуальностью не обойдёшься)
4. Шаблон Publisher/Subscriber.
5. Параметризованные контейнеры (Generic'и или stl).
6. Интерфейсы.
7. Примеси (когда другим не обойдёшься)
8. Понимание того, что бизнес-логика НЕ ДОЛЖНА зависеть от GUI
по большому счёту- ВСЁ
никакой "высшей математики"
не..ну ещё...
9. Шаблон Декоратор
Это я к чему?
Просто к тому, что я тут пытался человека убедить, что "мой код простой как пробка".
Это код "ремесленника", который "знает три аккорда" и "лабает на них".
никакой "высшей математики"...
И да! Это не "повод для гордости".
Просто - делюсь.
Ну и:
10. Тесты. Просто тесты. "Всегда и везде".
вторник, 23 декабря 2014 г.
MindStream в движении. Развиваем "предметную область". Только код №4
По мотивам - MindStream в движении. Развиваем "предметную область". Только код №3
Делаем "подъём" от текущей диаграммы к "предыдущей".
Главное это - ImsDiagrammsHolder.
Только код.
Делаем "подъём" от текущей диаграммы к "предыдущей".
Главное это - ImsDiagrammsHolder.
Только код.
unit msInterfaces; interface uses System.Types, System.Classes, FMX.Graphics, System.UITypes, msSerializeInterfaces, Generics.Collections ; type ImsShape = interface; ImsShapeByPt = interface function ShapeByPt(const aPoint: TPointF): ImsShape; end;//ImsShapeByPt ImsShapesController = interface(ImsShapeByPt) procedure RemoveShape(const aShape: ImsShape); end;//ImsShapesController // - тут бы иметь МНОЖЕСТВЕННОЕ наследование интерфейсов, но Delphi его не поддерживает // А вот с UML - мы его ПОТОМ СГЕНЕРИРУЕМ TmsDrawContext = record // Контекст рисования. // "Лирика" - тут - http://habrahabr.ru/post/170125/ // Ну и "связанное" - https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) // // Зачем же НАМ нужен "контекст"? // // Всё - БАНАЛЬНО. Чтобы НЕ ТРОГАТЬ сигнатуры методов. Мысль понятна? public rCanvas : TCanvas; rMoving : Boolean; // - определяем, что текущий рисуемый примитив - двигается constructor Create(const aCanvas : TCanvas); end;//TmsDrawContext ImsDiagrammsHolder = interface; TmsMakeShapeContext = record public rStartPoint: TPointF; rShapesController: ImsShapesController; rDiagrammsHolder: ImsDiagrammsHolder; constructor Create(aStartPoint: TPointF; const aShapesController: ImsShapesController; aDiagrammsHolder: ImsDiagrammsHolder); end;//TmsMakeShapeContext TmsEndShapeContext = TmsMakeShapeContext; TmsDrawOptionsContext = record public rFillColor: TAlphaColor; rStrokeDash: TStrokeDash; rStrokeColor: TAlphaColor; rStrokeThickness: Single; constructor Create(const aCtx: TmsDrawContext); end;//TmsDrawOptionsContext ImsDiagramm = interface; TmsDiagrammsEnumerator = TEnumerator; ImsShapesProvider = interface(ImsPersistent) procedure ShapesForToolbarToList(aList: TStrings); end;//ImsShapesProvider ImsDiagrammsList = interface(ImsShapesProvider) function GetEnumerator: TmsDiagrammsEnumerator; function IndexOf(const anItem: ImsDiagramm): Integer; function AddNewDiagramm: ImsDiagramm; procedure AddDiagramm(const aDiagramm: ImsDiagramm); function SelectDiagramm(const aDiagrammName: String): ImsDiagramm; function FirstDiagramm: ImsDiagramm; procedure DiagrammsForToolbarToList(aList: TStrings); function pm_GetCount: Integer; property Count: Integer read pm_GetCount; end;//ImsDiagrammsList ImsShape = interface(ImsDiagrammsList) ['{70D5F6A0-1025-418B-959B-0CF524D8E394}'] procedure DrawTo(const aCtx: TmsDrawContext); function IsNeedsSecondClick : Boolean; procedure EndTo(const aCtx: TmsEndShapeContext); function ContainsPt(const aPoint: TPointF): Boolean; procedure MoveTo(const aFinishPoint: TPointF); function pm_GetStartPoint: TPointF; property StartPoint: TPointF read pm_GetStartPoint; end;//ImsShape TmsShapesEnumerator = TEnumerator ; ImsShapeCreator = interface function CreateShape(const aContext: TmsMakeShapeContext): ImsShape; end;//ImsShapeCreator ImsDiagrammsHolder = interface procedure UpToParent; // - сигнализируем о том, что нам надо перейти к РОДИТЕЛЬСКОЙ диаграмме procedure SwapParents; // - сигнализируем о том, что надо ПОМЕНЯТЬ местами РОДИТЕЛЬСКИЕ диаграммы function pm_GetCurrentDiagramms: ImsDiagrammsList; procedure pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); property CurrentDiagramms : ImsDiagrammsList read pm_GetCurrentDiagramms write pm_SetCurrentDiagramms; end;//ImsDiagrammsHolder TmsClickContext = record public rShapeCreator: ImsShapeCreator; rClickPoint: TPointF; rDiagrammsHolder : ImsDiagrammsHolder; constructor Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); end;//TmsClickContext ImsDiagramm = interface(ImsShapesProvider) ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function Get_Name: String; procedure Invalidate; procedure ProcessClick(const aClickContext: TmsClickContext); procedure Clear; procedure DrawTo(const aCanvas: TCanvas); function AddShape(const aShape: ImsShape): ImsShape; function GetEnumerator: TmsShapesEnumerator; function ItemsCount: Integer; property Name: String read Get_Name; end;//ImsDiagramm ImsDiagramms = interface(ImsDiagrammsList) ['{819BEEBA-97BB-48F1-906E-107E67706D19}'] procedure Serialize; procedure DeSerialize; end;//ImsDiagramms ImsIvalidator = interface procedure InvalidateDiagramm(const aDiagramm: ImsDiagramm); procedure DiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); end;//ImsIvalidator ImsDiagrammsController = interface procedure Clear; procedure DrawTo(const aCanvas: TCanvas); end;//ImsDiagrammsController implementation // TmsDrawContext constructor TmsDrawContext.Create(const aCanvas : TCanvas); begin rCanvas := aCanvas; rMoving := false; end; // TmsMakeShapeContext constructor TmsMakeShapeContext.Create(aStartPoint: TPointF; const aShapesController: ImsShapesController; aDiagrammsHolder: ImsDiagrammsHolder); begin rStartPoint := aStartPoint; rShapesController := aShapesController; rDiagrammsHolder := aDiagrammsHolder; end; // TmsDrawOptionsContext constructor TmsDrawOptionsContext.Create(const aCtx: TmsDrawContext); begin rFillColor := TAlphaColorRec.Null; if aCtx.rMoving then begin rStrokeDash := TStrokeDash.sdDashDot; rStrokeColor := TAlphaColors.Darkmagenta; rStrokeThickness := 4; end//aCtx.rMoving else begin rStrokeDash := TStrokeDash.sdSolid; rStrokeColor := TAlphaColorRec.Black; rStrokeThickness := 1; end;//aCtx.rMoving end; // TmsClickContext constructor TmsClickContext.Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); begin rShapeCreator := aShapeCreator; rClickPoint := aClickPoint; rDiagrammsHolder := aDiagrammsHolder; end; end.
понедельник, 22 декабря 2014 г.
Ссылка. How do I pretty-print JSON in Delphi?
http://stackoverflow.com/questions/18511333/how-do-i-pretty-print-json-in-delphi
Я лично - вряд ли буду этим пользоваться. Скорости - не добавляет.
Хотя в нашем "макете" - это сейчас используется. Чисто - "поиграться".
Равно как и "стандартную сериализацию в JSON". Тоже - чисто "поиграться".
Далее будем использовать либо сериализацию через TPersistent либо вообще в EVD.
Я лично - вряд ли буду этим пользоваться. Скорости - не добавляет.
Хотя в нашем "макете" - это сейчас используется. Чисто - "поиграться".
Равно как и "стандартную сериализацию в JSON". Тоже - чисто "поиграться".
Далее будем использовать либо сериализацию через TPersistent либо вообще в EVD.
воскресенье, 21 декабря 2014 г.
суббота, 20 декабря 2014 г.
MindStream в движении. Развиваем "предметную область". Только код №3
По мотивам - MindStream в движении. Развиваем "предметную область". Только код №2
- ну что сказать? Мы ГОТОВИМСЯ к проваливанию ВНУТРЬ примитива. Для этого "подтачиваем" наши интерфейсы.
https://bitbucket.org/ingword/mindstream/src/6f0b5fa223241aa5a3ec2128e1048183264275fb/msInterfaces.pas?at=MS-7_Lulin_Upgrade
Только код.
- ну что сказать? Мы ГОТОВИМСЯ к проваливанию ВНУТРЬ примитива. Для этого "подтачиваем" наши интерфейсы.
https://bitbucket.org/ingword/mindstream/src/6f0b5fa223241aa5a3ec2128e1048183264275fb/msInterfaces.pas?at=MS-7_Lulin_Upgrade
Только код.
unit msInterfaces; interface uses System.Types, System.Classes, FMX.Graphics, System.UITypes, msSerializeInterfaces, Generics.Collections ; type ImsShape = interface; ImsShapeByPt = interface function ShapeByPt(const aPoint: TPointF): ImsShape; end;//ImsShapeByPt ImsShapesController = interface(ImsShapeByPt) procedure RemoveShape(const aShape: ImsShape); end;//ImsShapesController // - тут бы иметь МНОЖЕСТВЕННОЕ наследование интерфейсов, но Delphi его не поддерживает // А вот с UML - мы его ПОТОМ СГЕНЕРИРУЕМ TmsDrawContext = record // Контекст рисования. // "Лирика" - тут - http://habrahabr.ru/post/170125/ // Ну и "связанное" - https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) // // Зачем же НАМ нужен "контекст"? // // Всё - БАНАЛЬНО. Чтобы НЕ ТРОГАТЬ сигнатуры методов. Мысль понятна? public rCanvas : TCanvas; rMoving : Boolean; // - определяем, что текущий рисуемый примитив - двигается constructor Create(const aCanvas : TCanvas); end;//TmsDrawContext ImsDiagrammsHolder = interface; TmsMakeShapeContext = record public rStartPoint: TPointF; rShapesController: ImsShapesController; rDiagrammsHolder: ImsDiagrammsHolder; constructor Create(aStartPoint: TPointF; const aShapesController: ImsShapesController; aDiagrammsHolder: ImsDiagrammsHolder); end;//TmsMakeShapeContext TmsEndShapeContext = TmsMakeShapeContext; TmsDrawOptionsContext = record public rFillColor: TAlphaColor; rStrokeDash: TStrokeDash; rStrokeColor: TAlphaColor; rStrokeThickness: Single; constructor Create(const aCtx: TmsDrawContext); end;//TmsDrawOptionsContext ImsDiagramm = interface; TmsDiagrammsEnumerator = TEnumerator; ImsShapesProvider = interface(ImsPersistent) procedure ShapesForToolbarToList(aList: TStrings); end;//ImsShapesProvider ImsDiagrammsList = interface(ImsShapesProvider) function GetEnumerator: TmsDiagrammsEnumerator; function IndexOf(const anItem: ImsDiagramm): Integer; function AddNewDiagramm: ImsDiagramm; procedure AddDiagramm(const aDiagramm: ImsDiagramm); function SelectDiagramm(const aDiagrammName: String): ImsDiagramm; end;//ImsDiagrammsList ImsShape = interface(ImsDiagrammsList) ['{70D5F6A0-1025-418B-959B-0CF524D8E394}'] procedure DrawTo(const aCtx: TmsDrawContext); function IsNeedsSecondClick : Boolean; procedure EndTo(const aCtx: TmsEndShapeContext); function ContainsPt(const aPoint: TPointF): Boolean; procedure MoveTo(const aFinishPoint: TPointF); function pm_GetStartPoint: TPointF; property StartPoint: TPointF read pm_GetStartPoint; end;//ImsShape TmsShapesEnumerator = TEnumerator ; ImsShapeCreator = interface function CreateShape(const aContext: TmsMakeShapeContext): ImsShape; end;//ImsShapeCreator ImsDiagrammsHolder = interface function pm_GetCurrentDiagramms: ImsDiagrammsList; procedure pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); property CurrentDiagramms : ImsDiagrammsList read pm_GetCurrentDiagramms write pm_SetCurrentDiagramms; end;//ImsDiagrammsHolder TmsClickContext = record public rShapeCreator: ImsShapeCreator; rClickPoint: TPointF; rDiagrammsHolder : ImsDiagrammsHolder; constructor Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); end;//TmsClickContext ImsDiagramm = interface(ImsShapesProvider) ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function Get_Name: String; procedure Invalidate; procedure ProcessClick(const aClickContext: TmsClickContext); procedure Clear; procedure DrawTo(const aCanvas: TCanvas); function AddShape(const aShape: ImsShape): ImsShape; function GetEnumerator: TmsShapesEnumerator; function ItemsCount: Integer; property Name: String read Get_Name; end;//ImsDiagramm ImsDiagramms = interface(ImsDiagrammsList) ['{819BEEBA-97BB-48F1-906E-107E67706D19}'] procedure Serialize; procedure DeSerialize; end;//ImsDiagramms ImsIvalidator = interface procedure InvalidateDiagramm(const aDiagramm: ImsDiagramm); procedure DiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); end;//ImsIvalidator ImsDiagrammsController = interface procedure Clear; procedure DrawTo(const aCanvas: TCanvas); end;//ImsDiagrammsController implementation // TmsDrawContext constructor TmsDrawContext.Create(const aCanvas : TCanvas); begin rCanvas := aCanvas; rMoving := false; end; // TmsMakeShapeContext constructor TmsMakeShapeContext.Create(aStartPoint: TPointF; const aShapesController: ImsShapesController; aDiagrammsHolder: ImsDiagrammsHolder); begin rStartPoint := aStartPoint; rShapesController := aShapesController; rDiagrammsHolder := aDiagrammsHolder; end; // TmsDrawOptionsContext constructor TmsDrawOptionsContext.Create(const aCtx: TmsDrawContext); begin rFillColor := TAlphaColorRec.Null; if aCtx.rMoving then begin rStrokeDash := TStrokeDash.sdDashDot; rStrokeColor := TAlphaColors.Darkmagenta; rStrokeThickness := 4; end//aCtx.rMoving else begin rStrokeDash := TStrokeDash.sdSolid; rStrokeColor := TAlphaColorRec.Black; rStrokeThickness := 1; end;//aCtx.rMoving end; // TmsClickContext constructor TmsClickContext.Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); begin rShapeCreator := aShapeCreator; rClickPoint := aClickPoint; rDiagrammsHolder := aDiagrammsHolder; end; end.
MindStream в движении. Развиваем "предметную область". Только код №2
По мотивам - MindStream в движении. Развиваем "предметную область". Только код
Оказалось, что TmsDiagrammsController - ПАДАЕТ в результате предыдущих коммитов.
ПОЧЕМУ?
Объяснять - НЕ БУДУ.
Намекну - "из-за ImsDiagrammsHolder".
"используем ImsDiagrammsController, а НЕ TmsDiagrammsController. Embarcadero нас к этому ТОЛКАЕТ."
https://bitbucket.org/ingword/mindstream/src/fd5306a0575a10f8a8bf10bedeca955af9788caa/msInterfaces.pas?at=MS-7_Lulin_Upgrade
Только код.
А вообще на Borland и Embarcadero - "у меня давно зуб".
Оказалось, что TmsDiagrammsController - ПАДАЕТ в результате предыдущих коммитов.
ПОЧЕМУ?
Объяснять - НЕ БУДУ.
Намекну - "из-за ImsDiagrammsHolder".
"используем ImsDiagrammsController, а НЕ TmsDiagrammsController. Embarcadero нас к этому ТОЛКАЕТ."
https://bitbucket.org/ingword/mindstream/src/fd5306a0575a10f8a8bf10bedeca955af9788caa/msInterfaces.pas?at=MS-7_Lulin_Upgrade
Только код.
unit msInterfaces; interface uses System.Types, System.Classes, FMX.Graphics, System.UITypes, msSerializeInterfaces, Generics.Collections ; type ImsShape = interface; ImsShapeByPt = interface function ShapeByPt(const aPoint: TPointF): ImsShape; end;//ImsShapeByPt ImsShapesController = interface(ImsShapeByPt) procedure RemoveShape(const aShape: ImsShape); end;//ImsShapesController // - тут бы иметь МНОЖЕСТВЕННОЕ наследование интерфейсов, но Delphi его не поддерживает // А вот с UML - мы его ПОТОМ СГЕНЕРИРУЕМ TmsDrawContext = record // Контекст рисования. // "Лирика" - тут - http://habrahabr.ru/post/170125/ // Ну и "связанное" - https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) // // Зачем же НАМ нужен "контекст"? // // Всё - БАНАЛЬНО. Чтобы НЕ ТРОГАТЬ сигнатуры методов. Мысль понятна? public rCanvas : TCanvas; rMoving : Boolean; // - определяем, что текущий рисуемый примитив - двигается constructor Create(const aCanvas : TCanvas); end;//TmsDrawContext TmsMakeShapeContext = record public rStartPoint: TPointF; rShapesController: ImsShapesController; constructor Create(aStartPoint: TPointF; const aShapesController: ImsShapesController); end;//TmsMakeShapeContext TmsEndShapeContext = TmsMakeShapeContext; TmsDrawOptionsContext = record public rFillColor: TAlphaColor; rStrokeDash: TStrokeDash; rStrokeColor: TAlphaColor; rStrokeThickness: Single; constructor Create(const aCtx: TmsDrawContext); end;//TmsDrawOptionsContext ImsDiagramm = interface; TmsDiagrammsEnumerator = TEnumerator; ImsShapesProvider = interface(ImsPersistent) procedure ShapesForToolbarToList(aList: TStrings); end;//ImsShapesProvider ImsDiagrammsList = interface(ImsShapesProvider) function GetEnumerator: TmsDiagrammsEnumerator; function IndexOf(const anItem: ImsDiagramm): Integer; function AddNewDiagramm: ImsDiagramm; procedure AddDiagramm(const aDiagramm: ImsDiagramm); function SelectDiagramm(const aDiagrammName: String): ImsDiagramm; end;//ImsDiagrammsList ImsShape = interface(ImsDiagrammsList) ['{70D5F6A0-1025-418B-959B-0CF524D8E394}'] procedure DrawTo(const aCtx: TmsDrawContext); function IsNeedsSecondClick : Boolean; procedure EndTo(const aCtx: TmsEndShapeContext); function ContainsPt(const aPoint: TPointF): Boolean; procedure MoveTo(const aFinishPoint: TPointF); function pm_GetStartPoint: TPointF; property StartPoint: TPointF read pm_GetStartPoint; end;//ImsShape TmsShapesEnumerator = TEnumerator ; ImsShapeCreator = interface function CreateShape(const aContext: TmsMakeShapeContext): ImsShape; end;//ImsShapeCreator ImsDiagrammsHolder = interface function pm_GetCurrentDiagramms: ImsDiagrammsList; procedure pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); property CurrentDiagramms : ImsDiagrammsList read pm_GetCurrentDiagramms write pm_SetCurrentDiagramms; end;//ImsDiagrammsHolder TmsClickContext = record public rShapeCreator: ImsShapeCreator; rClickPoint: TPointF; rDiagrammsHolder : ImsDiagrammsHolder; constructor Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); end;//TmsClickContext ImsDiagramm = interface(ImsShapesProvider) ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function Get_Name: String; procedure Invalidate; procedure ProcessClick(const aClickContext: TmsClickContext); procedure Clear; procedure DrawTo(const aCanvas: TCanvas); function AddShape(const aShape: ImsShape): ImsShape; function GetEnumerator: TmsShapesEnumerator; function ItemsCount: Integer; property Name: String read Get_Name; end;//ImsDiagramm ImsDiagramms = interface(ImsDiagrammsList) ['{819BEEBA-97BB-48F1-906E-107E67706D19}'] procedure Serialize; procedure DeSerialize; end;//ImsDiagramms ImsIvalidator = interface procedure InvalidateDiagramm(const aDiagramm: ImsDiagramm); procedure DiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); end;//ImsIvalidator ImsDiagrammsController = interface procedure Clear; procedure DrawTo(const aCanvas: TCanvas); end;//ImsDiagrammsController implementation // TmsDrawContext constructor TmsDrawContext.Create(const aCanvas : TCanvas); begin rCanvas := aCanvas; rMoving := false; end; // TmsMakeShapeContext constructor TmsMakeShapeContext.Create(aStartPoint: TPointF; const aShapesController: ImsShapesController); begin rStartPoint := aStartPoint; rShapesController := aShapesController; end; // TmsDrawOptionsContext constructor TmsDrawOptionsContext.Create(const aCtx: TmsDrawContext); begin rFillColor := TAlphaColorRec.Null; if aCtx.rMoving then begin rStrokeDash := TStrokeDash.sdDashDot; rStrokeColor := TAlphaColors.Darkmagenta; rStrokeThickness := 4; end//aCtx.rMoving else begin rStrokeDash := TStrokeDash.sdSolid; rStrokeColor := TAlphaColorRec.Black; rStrokeThickness := 1; end;//aCtx.rMoving end; // TmsClickContext constructor TmsClickContext.Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF; const aDiagrammsHolder : ImsDiagrammsHolder); begin rShapeCreator := aShapeCreator; rClickPoint := aClickPoint; rDiagrammsHolder := aDiagrammsHolder; end; end. ... unit msDiagrammsController; interface uses {$Include msIvalidator.mixin.pas} , FMX.Objects, FMX.ListBox, FMX.StdCtrls, FMX.Graphics, msDiagramms, System.Types, FMX.Forms, System.Classes, System.UITypes, msCoreObjects, msInterfacedRefcounted, msShape, msInterfaces ; type TmsIvalidatorParent = TmsInterfacedRefcounted; {$Include msIvalidator.mixin.pas} TmsDiagrammsController = class(TmsIvalidator, ImsDiagrammsController) private imgMain: TPaintBox; cbShapes: TComboBox; cbDiagramm: TComboBox; btAddDiagramm: TButton; btSaveDiagramm: TButton; btLoadDiagramm: TButton; f_DiagrammsRoot: ImsDiagramms; f_CurrentDiagramms : ImsDiagrammsList; f_CurrentDiagramm : ImsDiagramm; procedure cbDiagrammChange(Sender: TObject); procedure btAddDiagrammClick(Sender: TObject); procedure imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); procedure btSaveDiagrammClick(Sender: TObject); procedure btLoadDiagrammClick(Sender: TObject); function pm_GetCurrentDiagramm: ImsDiagramm; procedure pm_SetCurrentDiagramm(const aValue: ImsDiagramm); function pm_GetCurrentDiagramms: ImsDiagrammsList; procedure pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); protected procedure DoInvalidateDiagramm(const aDiagramm: ImsDiagramm); override; procedure DoDiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); override; property CurrentDiagramms : ImsDiagrammsList read pm_GetCurrentDiagramms write pm_SetCurrentDiagramms; public constructor Create(aImage: TPaintBox; aShapes: TComboBox; aDiagramm: TComboBox; aAddDiagramm: TButton; aSaveDiagramm: TButton; aLoadDiagramm: TButton); destructor Destroy; override; procedure Clear; procedure ProcessClick(const aStart: TPointF); property CurrentDiagramm: ImsDiagramm read pm_GetCurrentDiagramm write pm_SetCurrentDiagramm; procedure DrawTo(const aCanvas: TCanvas); end;//TmsDiagrammsController implementation uses {$Include msIvalidator.mixin.pas} , System.SysUtils, FMX.Types, msShapesForToolbar, Math, msShapeCreator ; type TmsDiagrammsHolder = class(TmsInterfacedRefcounted, ImsDiagrammsHolder) private f_DiagrammsController : TmsDiagrammsController; constructor CreatePrim(aDiagrammsController : TmsDiagrammsController); protected function pm_GetCurrentDiagramms: ImsDiagrammsList; procedure pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); public class function Create(aDiagrammsController : TmsDiagrammsController): ImsDiagrammsHolder; end;//TmsDiagrammsHolder constructor TmsDiagrammsHolder.CreatePrim(aDiagrammsController : TmsDiagrammsController); begin inherited Create; f_DiagrammsController := aDiagrammsController; end; class function TmsDiagrammsHolder.Create(aDiagrammsController : TmsDiagrammsController): ImsDiagrammsHolder; begin Result := CreatePrim(aDiagrammsController); end; function TmsDiagrammsHolder.pm_GetCurrentDiagramms: ImsDiagrammsList; begin Result := f_DiagrammsController.CurrentDiagramms; end; procedure TmsDiagrammsHolder.pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); begin f_DiagrammsController.CurrentDiagramms := aValue; end; {$Include msIvalidator.mixin.pas} // TmsDiagrammsController constructor TmsDiagrammsController.Create(aImage: TPaintBox; aShapes: TComboBox; aDiagramm: TComboBox; aAddDiagramm: TButton; aSaveDiagramm: TButton; aLoadDiagramm: TButton); begin inherited Create; imgMain := aImage; cbShapes := aShapes; cbDiagramm := aDiagramm; btAddDiagramm := aAddDiagramm; btSaveDiagramm := aSaveDiagramm; btLoadDiagramm := aLoadDiagramm; cbDiagramm.OnChange := cbDiagrammChange; btAddDiagramm.OnClick := btAddDiagrammClick; btSaveDiagramm.OnClick := btSaveDiagrammClick; btLoadDiagramm.OnClick := btLoadDiagrammClick; imgMain.OnMouseDown := imgMainMouseDown; imgMain.Align := TAlignLayout.alClient; f_DiagrammsRoot := TmsDiagramms.Create; CurrentDiagramms := f_DiagrammsRoot; CurrentDiagramms.AddNewDiagramm; end; procedure TmsDiagrammsController.DoInvalidateDiagramm(const aDiagramm: ImsDiagramm); begin if (imgMain <> nil) then if (aDiagramm.EQ(CurrentDiagramm)) then imgMain.Repaint; end; function TmsDiagrammsController.pm_GetCurrentDiagramm: ImsDiagramm; begin Result := f_CurrentDiagramm; end; procedure TmsDiagrammsController.pm_SetCurrentDiagramm(const aValue: ImsDiagramm); begin if not aValue.EQ(f_CurrentDiagramm) then begin f_CurrentDiagramm := aValue; cbDiagramm.ItemIndex := cbDiagramm.Items.IndexOf(aValue.Name); f_CurrentDiagramm.Invalidate; end;//not aValue.EQ(f_CurrentDiagramm) end; function TmsDiagrammsController.pm_GetCurrentDiagramms: ImsDiagrammsList; begin Result := f_CurrentDiagramms; end; procedure TmsDiagrammsController.pm_SetCurrentDiagramms(const aValue: ImsDiagrammsList); var l_Index : Integer; begin if (f_CurrentDiagramms <> aValue) then begin f_CurrentDiagramms := aValue; l_Index := cbShapes.ItemIndex; cbShapes.Items.Clear; if (f_CurrentDiagramms <> nil) then begin f_CurrentDiagramms.ShapesForToolbarToList(cbShapes.Items); if (l_Index < 0) then if (cbShapes.Count > 0) then l_Index := 0; cbShapes.ItemIndex := Min(cbShapes.Count-1, l_Index); end;//f_CurrentDiagramms <> nil end;//f_CurrentDiagramms <> aValue end; procedure TmsDiagrammsController.btLoadDiagrammClick(Sender: TObject); var l_D : ImsDiagramm; l_I : Integer; begin l_I := cbDiagramm.ItemIndex; f_DiagrammsRoot.DeSerialize; cbDiagramm.Clear; Assert(f_DiagrammsRoot.EQ(CurrentDiagramms)); for l_D in f_DiagrammsRoot do cbDiagramm.Items.Add(l_D.Name); cbDiagramm.ItemIndex := l_I; end; procedure TmsDiagrammsController.btSaveDiagrammClick(Sender: TObject); begin f_DiagrammsRoot.Serialize; end; procedure TmsDiagrammsController.cbDiagrammChange(Sender: TObject); begin CurrentDiagramm := CurrentDiagramms.SelectDiagramm(cbDiagramm.Items[cbDiagramm.ItemIndex]); CurrentDiagramm.Invalidate; end; procedure TmsDiagrammsController.btAddDiagrammClick(Sender: TObject); begin CurrentDiagramms.AddNewDiagramm; end; destructor TmsDiagrammsController.Destroy; begin f_CurrentDiagramm := nil; CurrentDiagramms := nil; f_DiagrammsRoot := nil; inherited; end; procedure TmsDiagrammsController.Clear; begin CurrentDiagramm.Clear; end; procedure TmsDiagrammsController.ProcessClick(const aStart: TPointF); begin CurrentDiagramm.ProcessClick(TmsClickContext.Create(TmsShapeCreator.Create(TmsShapesForToolbar.Instance.Items[cbShapes.ItemIndex]), aStart, TmsDiagrammsHolder.Create(Self))); end; procedure TmsDiagrammsController.DrawTo(const aCanvas: TCanvas); begin CurrentDiagramm.DrawTo(aCanvas); end; procedure TmsDiagrammsController.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin Self.ProcessClick(TPointF.Create(X, Y)); end; procedure TmsDiagrammsController.DoDiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); begin Assert(CurrentDiagramms <> nil); if not CurrentDiagramms.EQ(aDiagramms) then Exit; if (CurrentDiagramms <> nil) then begin if (CurrentDiagramms.IndexOf(aDiagramm) >= 0) then begin cbDiagramm.Items.Add(aDiagramm.Name); CurrentDiagramm := aDiagramm; end;//CurrentDiagramms.IndexOf(aDiagramm) >= 0 end;//CurrentDiagramms <> nil end; end.
А вообще на Borland и Embarcadero - "у меня давно зуб".
MindStream в движении. Развиваем "предметную область". Только код
https://bitbucket.org/ingword/mindstream/src/d40b6c43974ba6ddeec818919d298418f953b409/msInterfaces.pas?at=MS-7_Lulin_Upgrade
unit msInterfaces; interface uses System.Types, System.Classes, FMX.Graphics, System.UITypes, msSerializeInterfaces, Generics.Collections ; type ImsShape = interface; ImsShapeByPt = interface function ShapeByPt(const aPoint: TPointF): ImsShape; end;//ImsShapeByPt ImsShapesController = interface(ImsShapeByPt) procedure RemoveShape(const aShape: ImsShape); end;//ImsShapesController // - тут бы иметь МНОЖЕСТВЕННОЕ наследование интерфейсов, но Delphi его не поддерживает // А вот с UML - мы его ПОТОМ СГЕНЕРИРУЕМ TmsDrawContext = record // Контекст рисования. // "Лирика" - тут - http://habrahabr.ru/post/170125/ // Ну и "связанное" - https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) // // Зачем же НАМ нужен "контекст"? // // Всё - БАНАЛЬНО. Чтобы НЕ ТРОГАТЬ сигнатуры методов. Мысль понятна? public rCanvas : TCanvas; rMoving : Boolean; // - определяем, что текущий рисуемый примитив - двигается constructor Create(const aCanvas : TCanvas); end;//TmsDrawContext TmsMakeShapeContext = record public rStartPoint: TPointF; rShapesController: ImsShapesController; constructor Create(aStartPoint: TPointF; const aShapesController: ImsShapesController); end;//TmsMakeShapeContext TmsEndShapeContext = TmsMakeShapeContext; TmsDrawOptionsContext = record public rFillColor: TAlphaColor; rStrokeDash: TStrokeDash; rStrokeColor: TAlphaColor; rStrokeThickness: Single; constructor Create(const aCtx: TmsDrawContext); end;//TmsDrawOptionsContext ImsDiagramm = interface; TmsDiagrammsEnumerator = TEnumerator; ImsShapesProvider = interface(ImsPersistent) procedure ShapesForToolbarToList(aList: TStrings); end;//ImsShapesProvider ImsDiagrammsList = interface(ImsShapesProvider) function GetEnumerator: TmsDiagrammsEnumerator; function IndexOf(const anItem: ImsDiagramm): Integer; function AddNewDiagramm: ImsDiagramm; procedure AddDiagramm(const aDiagramm: ImsDiagramm); end;//ImsDiagrammsList ImsShape = interface(ImsDiagrammsList) ['{70D5F6A0-1025-418B-959B-0CF524D8E394}'] procedure DrawTo(const aCtx: TmsDrawContext); function IsNeedsSecondClick : Boolean; procedure EndTo(const aCtx: TmsEndShapeContext); function ContainsPt(const aPoint: TPointF): Boolean; procedure MoveTo(const aFinishPoint: TPointF); function pm_GetStartPoint: TPointF; property StartPoint: TPointF read pm_GetStartPoint; end;//ImsShape TmsShapesEnumerator = TEnumerator ; ImsShapeCreator = interface function CreateShape(const aContext: TmsMakeShapeContext): ImsShape; end;//ImsShapeCreator ImsDiagrammsHolder = interface end;//ImsDiagrammsHolder TmsClickContext = record public rShapeCreator: ImsShapeCreator; rClickPoint: TPointF; constructor Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF); end;//TmsClickContext ImsDiagramm = interface(ImsShapesProvider) ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function Get_Name: String; procedure Invalidate; procedure ProcessClick(const aClickContext: TmsClickContext); procedure Clear; procedure DrawTo(const aCanvas: TCanvas); function AddShape(const aShape: ImsShape): ImsShape; function GetEnumerator: TmsShapesEnumerator; function ItemsCount: Integer; property Name: String read Get_Name; end;//ImsDiagramm ImsDiagramms = interface(ImsDiagrammsList) ['{819BEEBA-97BB-48F1-906E-107E67706D19}'] procedure Serialize; procedure DeSerialize; function SelectDiagramm(const aDiagrammName: String): ImsDiagramm; end;//ImsDiagramms ImsIvalidator = interface procedure InvalidateDiagramm(const aDiagramm: ImsDiagramm); procedure DiagrammAdded(const aDiagramms: ImsDiagrammsList; const aDiagramm: ImsDiagramm); end;//ImsIvalidator implementation // TmsDrawContext constructor TmsDrawContext.Create(const aCanvas : TCanvas); begin rCanvas := aCanvas; rMoving := false; end; // TmsMakeShapeContext constructor TmsMakeShapeContext.Create(aStartPoint: TPointF; const aShapesController: ImsShapesController); begin rStartPoint := aStartPoint; rShapesController := aShapesController; end; // TmsDrawOptionsContext constructor TmsDrawOptionsContext.Create(const aCtx: TmsDrawContext); begin rFillColor := TAlphaColorRec.Null; if aCtx.rMoving then begin rStrokeDash := TStrokeDash.sdDashDot; rStrokeColor := TAlphaColors.Darkmagenta; rStrokeThickness := 4; end//aCtx.rMoving else begin rStrokeDash := TStrokeDash.sdSolid; rStrokeColor := TAlphaColorRec.Black; rStrokeThickness := 1; end;//aCtx.rMoving end; // TmsClickContext constructor TmsClickContext.Create(const aShapeCreator: ImsShapeCreator; const aClickPoint: TPointF); begin rShapeCreator := aShapeCreator; rClickPoint := aClickPoint; end; end.
четверг, 18 декабря 2014 г.
среда, 17 декабря 2014 г.
Ссылка. DelphiArmy
http://jonlennartaasenden.wordpress.com/2014/12/16/delphiarmy-com-is-now-a-reality/
В двух словах, парень хочет сделать всемирный сайт поиска работы, для делфи программистов. На днях обещает запустить.
Коротко. О клиентах к git
Поставил сегодня себе на работе на Мак SmartGIT вместо SourceTree.
Не НАРАДУЮСЬ.
На больших объёмах он раз в СТО быстрее.
Хотя есть и минусы. Пользуюсь теперь обоими. Попеременно.
Не НАРАДУЮСЬ.
На больших объёмах он раз в СТО быстрее.
Хотя есть и минусы. Пользуюсь теперь обоими. Попеременно.
вторник, 16 декабря 2014 г.
понедельник, 15 декабря 2014 г.
суббота, 13 декабря 2014 г.
Ссылка. Интерфейсы vs. Абстрактные классы
http://sergeyteplyakov.blogspot.ru/2014/12/interfaces-vs-abstract-classes.html
Для Delphi эта статья - ОСОБЕННО АКТУАЛЬНО читается.
Особенно в "разрезе" InterlockedIncrenent.
В общем - "мои мысли" Тепляков - озвучил - "более чем".
Одно хочу добавить - у Теплякова нет "количественных оценок", а они - ИМХО - важны.
Если методов - "один-два-пять". Ну в крайнем случае - "десять", то это интерфейс.
Иначе это - "должен быть" - абстрактный класс.
Ибо "количественная оценка" говорит о том, что "такой интерфейс реализовать КРАЙНЕ сложно".
Я про "количественные оценки" и Интерфейсы vs. Абстрактные классы когда-то хотел написать.
Но потом - "забил". Понял, что "не поймут".
"Из своей практики" всё же добавлю.
Вот "это" - НЕ ИНТЕРФЕЙС.
А ужас:
Этот "интерфейс" - НЕВОЗМОЖНО реализовать. БОЛЕЕ одного раза.
Ибо он содержит в себе - МНОЖЕСТВО "побочных знаний".
И "протоколы взаимодействия".
А ЗНАЧИТ - это НЕ ИНТЕРФЕЙС, а "заготовка класса". Пусть и не ЧИСТО абстрактная. Пусть и ЧАСТИЧНО абстрактная.
То что я продемонстрировал выше - это ОДНО из десятков (а то и сотен) ИДИОТСКИХ проектных решений, которые я воплотил в жизнь. Могу продемонстрировать их ВСЕ. С ДЕТАЛЬНЫМ разбором. Был бы только толк.
И кстати - "до конца" проблема станет ясна только под AQTime.
Когда мы УВИДИМ накладные расходы на "подсчёт ссылок". Это уж если про "экономию на спичках".
БЕЗОТНОСИТЕЛЬНО того, что подобные "интерфейсы" в ПРИНЦИПЕ сложно реализовывать.
Или вот ещё:
Это тоже - УЖАС, а НЕ "интерфейс".
И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".
Для Delphi эта статья - ОСОБЕННО АКТУАЛЬНО читается.
Особенно в "разрезе" InterlockedIncrenent.
В общем - "мои мысли" Тепляков - озвучил - "более чем".
Одно хочу добавить - у Теплякова нет "количественных оценок", а они - ИМХО - важны.
Если методов - "один-два-пять". Ну в крайнем случае - "десять", то это интерфейс.
Иначе это - "должен быть" - абстрактный класс.
Ибо "количественная оценка" говорит о том, что "такой интерфейс реализовать КРАЙНЕ сложно".
Я про "количественные оценки" и Интерфейсы vs. Абстрактные классы когда-то хотел написать.
Но потом - "забил". Понял, что "не поймут".
"Из своей практики" всё же добавлю.
Вот "это" - НЕ ИНТЕРФЕЙС.
А ужас:
Il3Canvas = interface(Il3InfoCanvas) {* Канва для рисования } ['{F14964DA-11A9-490F-8D5C-A02BEAF85B84}'] function pm_GetWindowOrg: Tl3Point; procedure pm_SetWindowOrg(const aValue: Tl3Point); function pm_GetSWindowOrg: Tl3SPoint; procedure pm_SetSWindowOrg(const aValue: Tl3SPoint); function pm_GetClipRect: Tl3Rect; procedure pm_SetClipRect(const aValue: Tl3Rect); function pm_GetGlobalClipRect: Tl3Rect; function pm_GetBackColor: Tl3Color; procedure pm_SetBackColor(aValue: Tl3Color); function pm_GetDrawEnabled: Boolean; procedure pm_SetDrawEnabled(aValue: Boolean); function pm_GetDrawSpecial: Boolean; function pm_GetCanDrawSubs: Boolean; function pm_GetShowCursor: Boolean; procedure pm_SetShowCursor(aValue: Boolean); function pm_GetFontIndexSet: Tl3FontIndexes; procedure pm_SetFontIndexSet(aValue: Tl3FontIndexes); function pm_GetPrinted: Boolean; procedure pm_SetPrinted(aValue: Boolean); function pm_GetPenWidth: Integer; function pm_GetPageOrientation: Tl3PageOrientation; procedure pm_SetPageOrientation(aValue: Tl3PageOrientation); function pm_GetSectionExtent: Tl3Point; procedure pm_SetSectionExtent(const aValue: Tl3Point); procedure pm_SetNotFocused(aValue: Boolean); function pm_GetRegionBottomRight: Tl3Point; function Get_EffectiveColors: Il3EffectiveColors; function pm_GetPageSetup: Il3PageSetup; procedure pm_SetPainter(const aValue: Il3HAFPainter); function pm_GetCanvas: TCanvas; function Get_AbortChecker: Il3AbortChecker; procedure Set_AbortChecker(const aValue: Il3AbortChecker); procedure MoveWindowOrg(const Delta: Tl3Point); overload; procedure MoveWindowOrg(const Delta: Tl3SPoint); overload; procedure FillForeRect(const R: Tl3SRect); procedure FillRect(const R: Tl3SRect); overload; procedure FillRect(const R: Tl3Rect); overload; procedure FillEmptyRect(const R: Tl3Rect); overload; procedure FillEmptyRect(const R: Tl3SRect); overload; function FillRgn(const Region: Il3Region): Boolean; function TextOut(const P: Tl3Point; const S: Tl3PCharLen; FC: Tl3Color = clDefault; BC: Tl3Color = clDefault): Tl3Point; procedure SetCaret(const Origin: Tl3Point; const Extent: Tl3Point; Hidden: Boolean = false); procedure IncCaret(aDeltaX: Integer); procedure BeginPaint; procedure StartObject(anObjectID: Integer); procedure SetPageTop; procedure EndPaint; function DrawRgnOrBlock: Boolean; function HasToDraw: Boolean; procedure StretchDraw(const R: Tl3Rect; Graphic: VCLGraphic); procedure DrawSub(const aSubTarget: IUnknown; const R: Tl3Rect; LayerHandle: Integer; const aSub: IUnknown); procedure ExtTextOut(const P: Tl3Point; const R: Tl3Rect; const S: Tl3WString; F: Tl3TextFormatFlag = l3_tffLeft; Dx: PInteger = nil); overload; procedure ExtTextOut(const P: Tl3SPoint; const R: Tl3SRect; const S: Tl3WString; F: Tl3TextFormatFlag = l3_tffLeft; Dx: PInteger = nil); overload; function CaretLineOut(const aSt: Tl3WString; LineHeight: Integer; aHidden: Boolean; var CaretPos: Integer): Tl3Point; {* выводит строку текста высотой LineHeight, со сдвигом курсора отрисовки. устанавливает курсор в CaretPos. возвращает размеры выведенной строки. } function StringOut(const P: Tl3Point; const Text: Tl3WString): Tl3Point; procedure TabbedTextOut(const P: Tl3Point; const R: Tl3Rect; const S: Tl3WString; const aTabStops: Il3TabStops); overload; procedure TabbedTextOut(const P: Tl3SPoint; const R: Tl3SRect; const S: Tl3WString; const aTabStops: Il3TabStops); overload; function NewPage(ByWidth: Boolean = false): Boolean; {* начать новую страницу. } procedure Line(const A: Tl3Point; const B: Tl3Point); overload; {* нарисовать линию. } procedure Line(const A: Tl3SPoint; const B: Tl3SPoint); overload; {* нарисовать линию. } procedure MoveTo(const Pt: Tl3Point); overload; procedure LineTo(const Pt: Tl3Point); overload; procedure MoveTo(const Pt: Tl3SPoint); overload; procedure LineTo(const Pt: Tl3SPoint); overload; function WO(const aRect: Tl3Rect): Tl3SRect; overload; function WO(const aPt: Tl3Point): Tl3SPoint; overload; function WO(const aPt: Tl3SPoint): Tl3SPoint; overload; procedure DrawFocusRect(const aRect: Tl3SRect); procedure StartRegion; procedure FinishRegion; procedure PushWO; procedure PopWO; function GetClientRect: Tl3Rect; property WindowOrg: Tl3Point read pm_GetWindowOrg write pm_SetWindowOrg; {* смещение начала координат в дюймах. } property SWindowOrg: Tl3SPoint read pm_GetSWindowOrg write pm_SetSWindowOrg; {* смещение начала координат в пикселях. } property ClipRect: Tl3Rect read pm_GetClipRect write pm_SetClipRect; {* прямоугольник отсечения. } property GlobalClipRect: Tl3Rect read pm_GetGlobalClipRect; property BackColor: Tl3Color read pm_GetBackColor write pm_SetBackColor; property DrawEnabled: Boolean read pm_GetDrawEnabled write pm_SetDrawEnabled; {* разрешено рисование? } property DrawSpecial: Boolean read pm_GetDrawSpecial; {* рисовать спецсимволы? } property CanDrawSubs: Boolean read pm_GetCanDrawSubs; {* можем рисовать Sub'ы? } property ShowCursor: Boolean read pm_GetShowCursor write pm_SetShowCursor; {* отображать курсор? } property FontIndexSet: Tl3FontIndexes read pm_GetFontIndexSet write pm_SetFontIndexSet; {* текущий набор индексов шрифта. } property Printed: Boolean read pm_GetPrinted write pm_SetPrinted; {* все напечатано? } property PenWidth: Integer read pm_GetPenWidth; {* ширина пера. } property PageOrientation: Tl3PageOrientation read pm_GetPageOrientation write pm_SetPageOrientation; {* ориентация страницы. } property SectionExtent: Tl3Point read pm_GetSectionExtent write pm_SetSectionExtent; {* размеры текущего раздела с дюймах. } property NotFocused: Boolean write pm_SetNotFocused; property RegionBottomRight: Tl3Point read pm_GetRegionBottomRight; property EffectiveColors: Il3EffectiveColors read Get_EffectiveColors; property PageSetup: Il3PageSetup read pm_GetPageSetup; property Painter: Il3HAFPainter write pm_SetPainter; property Canvas: TCanvas read pm_GetCanvas; property AbortChecker: Il3AbortChecker read Get_AbortChecker write Set_AbortChecker; // Ml3WindowOrg function Get_InitialDCOffset: Tl3Point; function Get_InitialDCOffsetStored: Tl3Point; property InitialDCOffset: Tl3Point read Get_InitialDCOffset; property InitialDCOffsetStored: Tl3Point read Get_InitialDCOffsetStored; // Ml3CanvasState procedure Set_ClipRegion(const aValue: Il3Region); function PushClipRect: Tl3Rect; procedure PopClipRect; property ClipRegion: Il3Region write Set_ClipRegion; // Ml3CanvasInvert function pm_GetInvert: Boolean; procedure BeginInvert; procedure EndInvert; property Invert: Boolean read pm_GetInvert; end;//Il3Canvas
Этот "интерфейс" - НЕВОЗМОЖНО реализовать. БОЛЕЕ одного раза.
Ибо он содержит в себе - МНОЖЕСТВО "побочных знаний".
И "протоколы взаимодействия".
А ЗНАЧИТ - это НЕ ИНТЕРФЕЙС, а "заготовка класса". Пусть и не ЧИСТО абстрактная. Пусть и ЧАСТИЧНО абстрактная.
То что я продемонстрировал выше - это ОДНО из десятков (а то и сотен) ИДИОТСКИХ проектных решений, которые я воплотил в жизнь. Могу продемонстрировать их ВСЕ. С ДЕТАЛЬНЫМ разбором. Был бы только толк.
И кстати - "до конца" проблема станет ясна только под AQTime.
Когда мы УВИДИМ накладные расходы на "подсчёт ссылок". Это уж если про "экономию на спичках".
БЕЗОТНОСИТЕЛЬНО того, что подобные "интерфейсы" в ПРИНЦИПЕ сложно реализовывать.
Или вот ещё:
Ik2Tag = interface(Ik2Base) {* Объект содержащий подъобекты и атомарные атрибуты } ['{2345D08B-36E3-4B6A-ABA8-82C74B3431DF}'] {iterator} function IterateChildrenF(anAction: Ik2Tag_IterateChildrenF_Action; aLo: Tl3Index = l3MinIndex; aHi: Tl3Index = l3MaxIndex; aLoadedOnly: Boolean = false): Integer; {iterator} function IterateChildrenBack(anAction: Ik2Tag_IterateChildrenBack_Action; aHi: Tl3Index = l3MaxIndex; aLo: Tl3Index = l3MinIndex; aLoadedOnly: Boolean = false): Integer; {iterator} function IterateChildrenBackF(anAction: Ik2Tag_IterateChildrenBack_Action; aHi: Tl3Index = l3MaxIndex; aLo: Tl3Index = l3MinIndex; aLoadedOnly: Boolean = false): Integer; {iterator} procedure IterateProperties(anAction: Ik2Tag_IterateProperties_Action; anAll: Boolean {* Перебирать все возможные свойства или только РЕАЛЬНО заданные}); {* перебирает все существующие свойства } {iterator} procedure IteratePropertiesF(anAction: Ik2Tag_IterateProperties_Action; anAll: Boolean {* Перебирать все возможные свойства или только РЕАЛЬНО заданные}); {* перебирает все существующие свойства } function Box: Ik2Tag; {* ссылка на тег - для сохранения. } function IsSame(const aTag: Ik2Tag): Boolean; {* указывает, что инструменты работают с одним и тем же тегом. } procedure CheckSort(aProp: Tk2ArrayPropertyPrim); function AssignTag(const Source: Ik2Tag; AssignMode: Tk2AssignModes = k2_amAll; const Context: Ik2Op = nil): Boolean; function CloneTag: Ik2Tag; procedure AssignCloneParams(const aSource: Ik2Tag; AssignMode: Tk2AssignModes = k2_amAll; const Context: Ik2Op = nil); procedure Write(const G: Ik2TagGenerator; Flags: Tk2StorePropertyFlags = l3_spfAll; Exclude: TByteSet = []); {* записать тег в генератор. } // Mk2Value function pm_GetAsString: AnsiString; function pm_GetAsPCharLen: Tl3PCharLen; function AsBool: Boolean; {* преобразовать к Boolean. } function AsLong: Integer; function AsObject: TObject; property AsString: AnsiString read pm_GetAsString; {* свойство для преобразования к строкам Delphi } property AsPCharLen: Tl3PCharLen read pm_GetAsPCharLen; {* свойство для преобразования к типу Tl3PCharLen } // Mk2TypeInfo function IsOrd: Boolean; function InheritsFrom(anID: Integer): Boolean; overload; {* проверить наследование. } function InheritsFrom(const anIDs: array of Integer): Boolean; overload; {* проверить наследование. } function InheritsFrom(anAtomTypeID: Integer; const Exclude: array of Integer): Boolean; overload; {* проверить наследование. } // Mk2Children function pm_GetChildrenCount: Integer; function pm_GetChild(anIndex: Integer): Ik2Tag; procedure Set_ChildrenCapacity(aValue: Integer); function AddChild(var aChild: Ik2Tag; const aContext: Ik2Op = nil): Integer; {* добавить ребенка. } procedure InsertChild(anIndex: Integer; var aChild: Ik2Tag; const aContext: Ik2Op = nil); {* вставить ребенка. } function IndexOfChild(const aChild: Ik2Tag): Integer; function FindChild(anAtom: Integer; aValue: Integer; const aContext: Ik2Op = nil; aNeedCreate: Boolean = false; theIndex: PLong = nil): Ik2Tag; procedure DeleteChildren(const Context: Ik2Op = nil); {* удалить всех детей. } function DeleteChild(anIndex: Integer; const anOp: Ik2Op; out theChild: Ik2Tag): Boolean; overload; {* удалить ребенка. } function DeleteChild(const aChild: Ik2Tag; const Context: Ik2Op = nil): Boolean; overload; {* удалить ребенка. } function DeleteChild(anIndex: Integer; const anOp: Ik2Op = nil): Boolean; overload; property ChildrenCount: Integer read pm_GetChildrenCount; {* Количество дочерних тегов. } property Child[anIndex: Integer]: Ik2Tag read pm_GetChild; property ChildrenCapacity: Integer write Set_ChildrenCapacity; {* Потенциально возможное число детей } // Mk2RefCount function IntRef: Integer; procedure SetIntRef(out aRef: Integer); // Mk2Storable procedure DoLoad; procedure ForceStore; function MarkModified: Boolean; // Mk2Owned function Get_Owner: Ik2Tag; procedure Set_Owner(const aValue: Ik2Tag); property Owner: Ik2Tag read Get_Owner write Set_Owner; // Mk2IntegerHolder function pm_GetIntA(anIndex: Integer): Integer; procedure pm_SetIntA(anIndex: Integer; aValue: Integer); procedure pm_SetIntW(anIndex: Integer; const aContext: Ik2Op; aValue: Integer); function RLong(anIndex: Integer; aDefault: Integer): Integer; property IntA[anIndex: Integer]: Integer read pm_GetIntA write pm_SetIntA; property IntW[anIndex: Integer; const aContext: Ik2Op]: Integer write pm_SetIntW; // Mk2PCharLenHolder function pm_GetPCharLenA(anIndex: Integer): Tl3PCharLen; procedure pm_SetPCharLenA(anIndex: Integer; const aValue: Tl3PCharLen); procedure pm_SetPCharLenW(anIndex: Integer; const aContext: Ik2Op; const aValue: Tl3WString); property PCharLenA[anIndex: Integer]: Tl3PCharLen read pm_GetPCharLenA write pm_SetPCharLenA; property PCharLenW[anIndex: Integer; const aContext: Ik2Op]: Tl3WString write pm_SetPCharLenW; // Mk2BooleanHolder function pm_GetBoolA(anIndex: Integer): Boolean; procedure pm_SetBoolA(anIndex: Integer; aValue: Boolean); procedure pm_SetBoolW(anIndex: Integer; const aContext: Ik2Op; aValue: Boolean); function RBool(anIndex: Integer; aDefault: Boolean): Boolean; property BoolA[anIndex: Integer]: Boolean read pm_GetBoolA write pm_SetBoolA; property BoolW[anIndex: Integer; const aContext: Ik2Op]: Boolean write pm_SetBoolW; // Mk2StringHolder function pm_GetStrA(anIndex: Integer): AnsiString; procedure pm_SetStrA(anIndex: Integer; const aValue: AnsiString); procedure pm_SetStrW(anIndex: Integer; const aContext: Ik2Op; const aValue: AnsiString); property StrA[anIndex: Integer]: AnsiString read pm_GetStrA write pm_SetStrA; property StrW[anIndex: Integer; const aContext: Ik2Op]: AnsiString write pm_SetStrW; // Mk2ObjectHolder procedure pm_SetObjW(anIndex: Integer; const aContext: Ik2Op; aValue: TObject); property ObjW[anIndex: Integer; const aContext: Ik2Op]: TObject write pm_SetObjW; // Mk2TypeHolder function pm_GetTagType: Tk2TypePrim; property TagType: Tk2TypePrim read pm_GetTagType; // Mk2TagHolder function pm_GetAttr(anIndex: Integer): Ik2Tag; procedure pm_SetAttr(anIndex: Integer; const aValue: Ik2Tag); procedure pm_SetAttrW(anIndex: Integer; const aContext: Ik2Op; const aValue: Ik2Tag); function RAtomEx(const Path: array of Integer; theIndex: PLong = nil): Ik2Tag; {* вернуть подтег. } function ROwnAtom(anIndex: Integer): Ik2Tag; function CAtom(anIndex: Integer; const aContext: Ik2Op = nil; anAtomType: Tk2TypePrim = nil): Ik2Tag; {* проверить существование подтега и создать его при необходимости. } function CAtomEx(const aPath: array of Integer; const aContext: Ik2Op; theIndex: PLong = nil): Ik2Tag; {* проверить существование подтега и создать его при необходимости. } property Attr[anIndex: Integer]: Ik2Tag read pm_GetAttr write pm_SetAttr; default; property AttrW[anIndex: Integer; const aContext: Ik2Op]: Ik2Tag write pm_SetAttrW; // Mk2Compare function CompareWithInt(aValue: Integer; anIndex: Integer): Integer; {* Сравнивает тег с целым. } function CompareWithTag(const aTag: Ik2Tag; aSortIndex: Tl3SortIndex): Integer; // Mk2AtomHolder function HasSubAtom(anIndex: Integer): Boolean; // Mk2TagInfo function IsNull: Boolean; {* пустой тег? } function IsValid: Boolean; {* тег имеет значение? } function IsTransparent: Boolean; {* тег "прозрачный"? } function IsStream(out theStream: IStream): Boolean; {* Проверяет может ли тег приводиться к потоку. И приводит к потоку - если указатель на поток - не нулевой. } // Mk2TagToolProvider function QT(const IID: TGUID; out Obj; const aProcessor: Ik2Processor = nil): Boolean; {* возвращает инструмент для работы с тегом, к которому привязан исходный инструмент. } // Mk2InterfaceProvider function GetOwnInterface(const IID: TGUID; out Obj): Boolean; {* возвращает интерфейс НЕПОСРЕДСТВЕННО поддерживаемый реализацией инструмента. } function GetLinkedInterface(const IID: TGUID; out Obj): Boolean; // Mk2Int64Holder function Get_Int64A(aTagID: Integer): Int64; procedure Set_Int64A(aTagID: Integer; aValue: Int64); procedure Set_Int64W(aTagID: Integer; const aContext: Ik2Op; aValue: Int64); property Int64A[aTagID: Integer]: Int64 read Get_Int64A write Set_Int64A; property Int64W[aTagID: Integer; const aContext: Ik2Op]: Int64 write Set_Int64W; end;//Ik2Tag
Это тоже - УЖАС, а НЕ "интерфейс".
И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".
пятница, 12 декабря 2014 г.
Offtopic. Offtopic. "О солнечной системе"
http://www.lib.ru/AKONANDOJL/sh_scarl.txt
"Невежество Холмса было так же поразительно, как и его знания. О
"Невежество Холмса было так же поразительно, как и его знания. О
современной литературе, политике и философии он почти не имел представления. Мне случилось упомянуть имя Томаса Карлейля, и Холмс наивно спросил, кто он такой и чем знаменит. Но когда оказалось, что он ровно ничего не знает ни о теории Коперника, ни о строении солнечной системы, я просто опешил от изумления. Чтобы цивилизованный человек, живущий в девятнадцатом веке, не знал, что Земля вертится вокруг Солнца, - этому я просто не мог поверить! - Вы, кажется, удивлены, - улыбнулся он, глядя на мое растерянное лицо. - Спасибо, что вы меня просветили, но теперь я постараюсь как можно скорее все это забыть. - Забыть?! - Видите ли, - сказал он, - мне представляется, что человеческий мозг похож на маленький пустой чердак, который вы можете обставить, как хотите. Дурак натащит туда всякой рухляди, какая попадется под руку, и полезные, нужные вещи уже некуда будет всунуть, или в лучшем случае до них среди всей этой завали и не докопаешься. А человек толковый тщательно отбирает то, что он поместит в свой мозговой чердак. Он возьмет лишь инструменты, которые понадобятся ему для работы, но зато их будет множество, и все он разложит в образцовом порядке. Напрасно люди думают, что у этой маленькой комнатки эластичные стены и их можно растягивать сколько угодно. Уверяю вас, придет время, когда, приобретая новое, вы будете забывать что-то из прежнего. Поэтому страшно важно, чтобы ненужные сведения не вытесняли собой нужных. - Да, но не знать о солнечной системе!.. - воскликнул я. - На кой черт она мне? - перебил он нетерпеливо. - Ну хорошо, пусть, как вы говорите, мы вращаемся вокруг Солнца. А если бы я узнал, что мы вращаемся вокруг Луны, много бы это помогло мне или моей работе?"
Про generic'и, "примеси", интерфейсы и енумераторы. Только код
Интерфейс:
Теперь примесь:
Обращаем внимание на:
TmsItemsListEnumerator = TEnumerator<TmsItem>
и
function GetEnumerator: TmsItemsListEnumerator.
Теперь реализация:
Ссылки:
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msInterfaces.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msItemsHolder.mixin.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msCustomDiagramms.pas?at=MS-7_Lulin_Upgrade
ImsDiagramm = interface(ImsObjectWrap) ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function Get_Name: String; procedure Invalidate; procedure ProcessClick(const aStart: TPointF); procedure Clear; procedure SelectShape(aList: TStrings; anIndex: Integer); procedure AllowedShapesToList(aList: TStrings); function CurrentShapeClassIndex: Integer; procedure DrawTo(const aCanvas: TCanvas); property Name: String read Get_Name; end;//ImsDiagramm TmsDiagrammsEnumerator = TEnumerator<ImsDiagramm>; ImsDiagramms = interface(ImsObjectWrap) ['{819BEEBA-97BB-48F1-906E-107E67706D19}'] procedure AllowedShapesToList(aList: TStrings); function CurrentShapeClassIndex: Integer; function CurrentDiagrammIndex: Integer; function pm_GetCurrentDiagramm: ImsDiagramm; procedure AddDiagramm(aList: TStrings); procedure Serialize; procedure DeSerialize; procedure Clear; procedure SelectDiagramm(anIndex: Integer); procedure SelectShape(aList: TStrings; anIndex: Integer); procedure ProcessClick(const aStart: TPointF); function GetEnumerator: TmsDiagrammsEnumerator; property CurrentDiagramm: ImsDiagramm read pm_GetCurrentDiagramm; end;//ImsDiagrammsОбращаем внимание на function GetEnumerator: TmsDiagrammsEnumerator.
Теперь примесь:
{$IfNDef TmsItemsHolder_uses_intf} // Объект содержащий список других объектов // interface {$Define TmsItemsHolder_uses_intf} // uses Generics.Collections, Data.DBXJSONReflect, System.Rtti {$Else TmsItemsHolder_uses_intf} {$IfNDef TmsItemsHolder_intf} // http://programmingmindstream.blogspot.ru/2014/12/generic-2.html {$Define TmsItemsHolder_intf} TmsRttiFieldLambda = reference to procedure (aField: TRttiField); TmsItemsList = TList<TmsItem>; TmsItemsListEnumerator = TEnumerator<TmsItem>; TmsItemsHolder = class(TmsItemsHolderParent) private [JSONMarshalled(True)] f_Items : TmsItemsList; function pm_GetItems: TmsItemsList; procedure pm_SetItems(aValue: TmsItemsList); class procedure RegisterItemsLike(aLambda: TmsRttiFieldLambda); public constructor Create; destructor Destroy; override; property Items: TmsItemsList read pm_GetItems write pm_SetItems; procedure Assign(anOther : TmsItemsHolder); class procedure RegisterInMarshal(aMarshal: TJSONMarshal); class procedure RegisterInUnMarshal(aMarshal: TJSONUnMarshal); function GetEnumerator: TmsItemsListEnumerator; end;//TmsItemsHolder {$Else TmsItemsHolder_intf} // implementation {$IfNDef TmsItemsHolder_uses_impl} // uses System.TypInfo {$Define TmsItemsHolder_uses_impl} {$Else TmsItemsHolder_uses_impl} // TmsItemsHolder constructor TmsItemsHolder.Create; begin inherited; Assert(f_Items = nil); f_Items := TmsItemsList.Create; end; destructor TmsItemsHolder.Destroy; begin FreeAndNil(f_Items); inherited; end; function TmsItemsHolder.pm_GetItems: TmsItemsList; begin if (f_Items = nil) then f_Items := TmsItemsList.Create; Result := f_Items; end; procedure TmsItemsHolder.pm_SetItems(aValue: TmsItemsList); var l_Item : TmsItem; begin if (f_Items <> nil) then f_Items.Clear; if (aValue <> nil) then for l_Item in aValue do begin if (f_Items = nil) then f_Items := TmsItemsList.Create; f_Items.Add(l_Item); end;//for l_Shape in aValue end; procedure TmsItemsHolder.Assign(anOther : TmsItemsHolder); begin Self.Items := anOther.Items; end; class procedure TmsItemsHolder.RegisterItemsLike(aLambda: TmsRttiFieldLambda); var l_Field : TRttiField; begin for l_Field in TRttiContext.Create.GetType(Self).GetFields do if (l_Field.Visibility = mvPrivate) then if (l_Field.Name = 'f_Items') then begin aLambda(l_Field); Exit; end;//l_Field.Name = 'f_Items' Assert(false, 'Не найдено поля для Items'); end; class procedure TmsItemsHolder.RegisterInMarshal(aMarshal: TJSONMarshal); begin RegisterItemsLike( procedure (aField: TRttiField) var l_FieldName : String; begin l_FieldName := aField.Name; aMarshal.RegisterConverter(Self, l_FieldName, function (Data: TObject; Field: String): TListOfObjects var l_Item: TmsItem; l_Index: Integer; begin Assert(Field = l_FieldName); SetLength(Result, (Data As TmsItemsHolder).Items.Count); l_Index := 0; for l_Item in (Data As TmsItemsHolder).Items do begin Result[l_Index] := l_Item.toObject; Inc(l_Index); end;//for l_Item end );//aMarshal.RegisterConverter end );//RegisterItemsLike aMarshal.RegisterJSONMarshalled(Self, 'FRefCount', false); end; class procedure TmsItemsHolder.RegisterInUnMarshal(aMarshal: TJSONUnMarshal); begin RegisterItemsLike( procedure (aField: TRttiField) var l_FieldName : String; begin l_FieldName := aField.Name; aMarshal.RegisterReverter(Self, l_FieldName, procedure (Data: TObject; Field: String; Args: TListOfObjects) var l_Object: TObject; l_Holder : TmsItemsHolder; l_ItemI : TmsItem; begin Assert(Field = l_FieldName); l_Holder := Data As TmsItemsHolder; Assert(l_Holder <> nil); for l_Object in Args do begin if Supports(l_Object, TmsItem, l_ItemI) then l_Holder.Items.Add(l_ItemI) else raise Exception.Create(l_Object.ClassName + ' не поддерживает нужный интерфейс'); end//for l_Object end );//aMarshal.RegisterReverter end );//RegisterItemsLike end; function TmsItemsHolder.GetEnumerator: TmsItemsListEnumerator; begin Result := f_Items.GetEnumerator; end; {$EndIf TmsItemsHolder_uses_impl} {$EndIf TmsItemsHolder_intf} {$EndIf TmsItemsHolder_uses_intf}
Обращаем внимание на:
TmsItemsListEnumerator = TEnumerator<TmsItem>
и
function GetEnumerator: TmsItemsListEnumerator.
Теперь реализация:
unit msCustomDiagramms; interface uses {$Include msItemsHolder.mixin.pas} , msShape, msDiagramm, msInterfaces, msDiagrammsPrim ; type TmsItemsHolderParent = TmsDiagrammsPrim; TmsItem = ImsDiagramm; {$Include msItemsHolder.mixin.pas} TmsCustomDiagramms = class abstract(TmsItemsHolder, ImsDiagramms) end;//TmsCustomDiagramms implementation uses {$Include msItemsHolder.mixin.pas} , System.SysUtils ; {$Include msItemsHolder.mixin.pas} end.
Ссылки:
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msInterfaces.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msItemsHolder.mixin.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/39ba55201bbe26fff14e321a7e216ab018bf6b22/msCustomDiagramms.pas?at=MS-7_Lulin_Upgrade
четверг, 11 декабря 2014 г.
Ещё про примеси. Отвязываем данные от View. Только код
По мотивам - Ещё про примеси. Выделяем класс-примесь TmsIvalidator. Только код
Теперь стало:
https://bitbucket.org/ingword/mindstream/src/e075ee861e2d86776e652391e443782b21da4071/msDiagrammsController.pas?at=MS-7_Lulin_Upgrade
Теперь стало:
https://bitbucket.org/ingword/mindstream/src/e075ee861e2d86776e652391e443782b21da4071/msDiagrammsController.pas?at=MS-7_Lulin_Upgrade
unit msDiagrammsController; interface uses {$Include msIvalidator.mixin.pas} , FMX.Objects, FMX.ListBox, FMX.StdCtrls, FMX.Graphics, msDiagramms, System.Types, FMX.Forms, System.Classes, System.UITypes, msCoreObjects, msWatchedObjectInstance, msInterfacedRefcounted ; type TmsIvalidatorParent = TmsInterfacedRefcounted; {$Include msIvalidator.mixin.pas} TmsDiagrammsController = class(TmsIvalidator) private imgMain: TPaintBox; cbShapes: TComboBox; cbDiagramm: TComboBox; btAddDiagramm: TButton; btSaveDiagramm: TButton; btLoadDiagramm: TButton; FDiagramms: TmsDiagramms; procedure cbDiagrammChange(Sender: TObject); procedure imgMainResize(Sender: TObject); procedure cbShapesChange(Sender: TObject); procedure btAddDiagrammClick(Sender: TObject); procedure imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); procedure btSaveDiagrammClick(Sender: TObject); procedure btLoadDiagrammClick(Sender: TObject); function pm_GetCurrentDiagramm: TmsDiagramm; protected procedure DoInvalidateDiagramm(aDiagramm: TmsDiagramm); override; public constructor Create(aImage: TPaintBox; aShapes: TComboBox; aDiagramm: TComboBox; aAddDiagramm: TButton; aSaveDiagramm: TButton; aLoadDiagramm: TButton); destructor Destroy; override; procedure Clear; procedure ProcessClick(const aStart: TPointF); property CurrentDiagramm: TmsDiagramm read pm_GetCurrentDiagramm; procedure DrawTo(const aCanvas: TCanvas); end;//TmsDiagrammsController implementation uses {$Include msIvalidator.mixin.pas} , System.SysUtils, FMX.Types ; {$Include msIvalidator.mixin.pas} // TmsDiagrammsController constructor TmsDiagrammsController.Create(aImage: TPaintBox; aShapes: TComboBox; aDiagramm: TComboBox; aAddDiagramm: TButton; aSaveDiagramm: TButton; aLoadDiagramm: TButton); begin inherited Create; imgMain := aImage; cbShapes := aShapes; cbDiagramm := aDiagramm; btAddDiagramm := aAddDiagramm; btSaveDiagramm := aSaveDiagramm; btLoadDiagramm := aLoadDiagramm; FDiagramms := TmsDiagramms.Create(cbDiagramm.Items); FDiagramms.AllowedShapesToList(cbShapes.Items); cbShapes.ItemIndex := FDiagramms.CurrentShapeClassIndex; cbDiagramm.ItemIndex := FDiagramms.CurrentDiagrammIndex; cbDiagramm.OnChange := cbDiagrammChange; imgMain.OnResize := imgMainResize; cbShapes.OnChange := cbShapesChange; btAddDiagramm.OnClick := btAddDiagrammClick; btSaveDiagramm.OnClick := btSaveDiagrammClick; btLoadDiagramm.OnClick := btLoadDiagrammClick; imgMain.OnMouseDown := imgMainMouseDown; imgMain.Align := TAlignLayout.alClient; end; procedure TmsDiagrammsController.DoInvalidateDiagramm(aDiagramm: TmsDiagramm); begin if (imgMain <> nil) then if (aDiagramm = CurrentDiagramm) then imgMain.Repaint; end; function TmsDiagrammsController.pm_GetCurrentDiagramm: TmsDiagramm; begin Result := FDiagramms.CurrentDiagramm; end; procedure TmsDiagrammsController.btLoadDiagrammClick(Sender: TObject); var l_D : ImsDiagramm; l_I : Integer; begin l_I := FDiagramms.CurrentDiagrammIndex; FDiagramms.DeSerialize; cbDiagramm.Clear; for l_D in FDiagramms.Items do cbDiagramm.Items.Add((l_D.toObject As TmsDiagramm).Name); cbDiagramm.ItemIndex := l_I; end; procedure TmsDiagrammsController.btSaveDiagrammClick(Sender: TObject); begin FDiagramms.Serialize; end; procedure TmsDiagrammsController.cbDiagrammChange(Sender: TObject); begin FDiagramms.SelectDiagramm(cbDiagramm.ItemIndex); cbShapes.ItemIndex := FDiagramms.CurrentShapeClassIndex; end; procedure TmsDiagrammsController.imgMainResize(Sender: TObject); begin end; procedure TmsDiagrammsController.cbShapesChange(Sender: TObject); begin FDiagramms.SelectShape(cbShapes.Items, cbShapes.ItemIndex); end; procedure TmsDiagrammsController.btAddDiagrammClick(Sender: TObject); begin FDiagramms.AddDiagramm(cbDiagramm.Items); cbDiagramm.ItemIndex := FDiagramms.CurrentDiagrammIndex; cbShapes.ItemIndex := FDiagramms.CurrentShapeClassIndex; end; destructor TmsDiagrammsController.Destroy; begin FreeAndNil(FDiagramms); inherited; end; procedure TmsDiagrammsController.Clear; begin FDiagramms.Clear; end; procedure TmsDiagrammsController.ProcessClick(const aStart: TPointF); begin FDiagramms.ProcessClick(aStart); end; procedure TmsDiagrammsController.DrawTo(const aCanvas: TCanvas); begin CurrentDiagramm.DrawTo(aCanvas); end; procedure TmsDiagrammsController.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin Self.ProcessClick(TPointF.Create(X, Y)); end; end.
Ещё про примеси. Выделяем класс-примесь TmsIvalidator. Только код
По мотивам - И ещё про "примеси". Только код
https://bitbucket.org/ingword/mindstream/src/b43af5d8e14b393491618198fbfd92dab64dd087/msDiagramms.pas?at=MS-7_Lulin_Upgrade
Было:
Стало:
https://bitbucket.org/ingword/mindstream/src/4a018ef0ba8d5c7ae8f8ee8bbde32c4803702337/msInvalidators.pas?at=master
https://bitbucket.org/ingword/mindstream/src/4a018ef0ba8d5c7ae8f8ee8bbde32c4803702337/msDiagramms.pas?at=master
msIvalidator.mixin.pas:
msDiagramms:
https://bitbucket.org/ingword/mindstream/src/b43af5d8e14b393491618198fbfd92dab64dd087/msDiagramms.pas?at=MS-7_Lulin_Upgrade
Было:
unit msDiagramms; interface uses msDiagramm, System.Types, FMX.Objects, System.Classes, msCoreObjects, msWatchedObjectInstance, msInterfacedNonRefcounted, msShape, msCustomDiagramms, Data.DBXJSONReflect ; type TmsDiagramms = class(TmsCustomDiagramms, ImsIvalidator) private [JSONMarshalled(True)] f_CurrentDiagramm : Integer; [JSONMarshalled(False)] f_Image: TPaintBox; function pm_GetCurrentDiagramm: TmsDiagramm; procedure InvalidateDiagramm(aDiagramm: TmsDiagramm); public constructor Create(anImage: TPaintBox; aList: TStrings); procedure AfterConstruction; override; procedure ProcessClick(const aStart: TPointF); procedure Clear; procedure SelectShape(aList: TStrings; anIndex: Integer); procedure AllowedShapesToList(aList: TStrings); procedure AddDiagramm(aList: TStrings); function CurrentDiagrammIndex: Integer; procedure SelectDiagramm(anIndex: Integer); function CurrentShapeClassIndex: Integer; procedure Serialize; procedure DeSerialize; property CurrentDiagramm: TmsDiagramm read pm_GetCurrentDiagramm; procedure Assign(anOther: TmsDiagramms); destructor Destroy; override; end;//TmsDiagramms implementation uses System.SysUtils, FMX.Graphics, System.UITypes, msDiagrammsMarshal, msRegisteredShapes, msInvalidators ; // TmsDiagramms constructor TmsDiagramms.Create(anImage: TPaintBox; aList: TStrings); begin inherited Create; f_Image := anImage; AddDiagramm(aList); end; procedure TmsDiagramms.AfterConstruction; begin TmsInvalidators.Subscribe(Self); inherited; end; destructor TmsDiagramms.Destroy; begin TmsInvalidators.UnSubscribe(Self); inherited; end; function TmsDiagramms.pm_GetCurrentDiagramm: TmsDiagramm; begin Result := Items[f_CurrentDiagramm].toObject As TmsDiagramm; end; procedure TmsDiagramms.InvalidateDiagramm(aDiagramm: TmsDiagramm); var l_Canvas : TCanvas; begin if (f_Image <> nil) then if (aDiagramm = CurrentDiagramm) then f_Image.Repaint; end; procedure TmsDiagramms.AddDiagramm(aList: TStrings); var l_D : ImsDiagramm; begin l_D := TmsDiagramm.Create('Диаграмма №' + IntToStr(Items.Count + 1)); Items.Add(l_D); f_CurrentDiagramm := Items.IndexOf(l_D); if (aList <> nil) then aList.Add(l_D.Name); end; function TmsDiagramms.CurrentDiagrammIndex: Integer; begin Result := f_CurrentDiagramm; end; procedure TmsDiagramms.SelectDiagramm(anIndex: Integer); begin if (anIndex < 0) OR (anIndex >= Items.Count) then Exit; f_CurrentDiagramm := anIndex; CurrentDiagramm.Invalidate; end; const c_FileName = 'All.json'; procedure TmsDiagramms.DeSerialize; begin TmsDiagrammsMarshal.DeSerialize(c_FileName, self); end; procedure TmsDiagramms.Assign(anOther: TmsDiagramms); var l_D : ImsDiagramm; begin inherited Assign(anOther); for l_D in Items do begin (l_D.toObject As TmsDiagramm).CurrentClass := TmsRegisteredShapes.Instance.First; end;//for l_D Self.f_CurrentDiagramm := anOther.CurrentDiagrammIndex; CurrentDiagramm.Invalidate; end; procedure TmsDiagramms.ProcessClick(const aStart: TPointF); begin CurrentDiagramm.ProcessClick(aStart); end; procedure TmsDiagramms.Clear; begin CurrentDiagramm.Clear; end; procedure TmsDiagramms.SelectShape(aList: TStrings; anIndex: Integer); begin CurrentDiagramm.SelectShape(aList, anIndex); end; procedure TmsDiagramms.Serialize; begin TmsDiagrammsMarshal.Serialize(c_FileName, self); end; procedure TmsDiagramms.AllowedShapesToList(aList: TStrings); begin CurrentDiagramm.AllowedShapesToList(aList); end; function TmsDiagramms.CurrentShapeClassIndex: Integer; begin Result := CurrentDiagramm.CurrentShapeClassIndex; end; end.
Стало:
https://bitbucket.org/ingword/mindstream/src/4a018ef0ba8d5c7ae8f8ee8bbde32c4803702337/msInvalidators.pas?at=master
https://bitbucket.org/ingword/mindstream/src/4a018ef0ba8d5c7ae8f8ee8bbde32c4803702337/msDiagramms.pas?at=master
msIvalidator.mixin.pas:
{$IfNDef TmsIvalidator_intf} // interface {$Define TmsIvalidator_intf} // uses msDiagramm {$Else TmsIvalidator_intf} {$IfNDef TmsMixIn_intf} // http://programmingmindstream.blogspot.ru/2014/12/generic-2.html TmsIvalidator = class(TmsIvalidatorParent, ImsIvalidator) private procedure InvalidateDiagramm(aDiagramm: TmsDiagramm); protected procedure DoInvalidateDiagramm(aDiagramm: TmsDiagramm); virtual; abstract; public procedure AfterConstruction; override; destructor Destroy; override; end;//TmsIvalidator {$Define TmsMixIn_intf} {$Else TmsMixIn_intf} // implementation {$IfNDef TmsIvalidator_impl} // uses {$Define TmsIvalidator_impl} {$Else TmsIvalidator_impl} // TmsIvalidator procedure TmsIvalidator.InvalidateDiagramm(aDiagramm: TmsDiagramm); begin DoInvalidateDiagramm(aDiagramm); end; procedure TmsIvalidator.AfterConstruction; begin TmsInvalidators.Subscribe(Self); inherited; end; destructor TmsIvalidator.Destroy; begin TmsInvalidators.UnSubscribe(Self); inherited; end; {$EndIf TmsIvalidator_impl} {$EndIf TmsMixIn_intf} {$EndIf TmsIvalidator_intf}
msDiagramms:
unit msDiagramms; interface uses {$Include msIvalidator.mixin.pas} , System.Types, FMX.Objects, System.Classes, msCoreObjects, msWatchedObjectInstance, msInterfacedNonRefcounted, msShape, msCustomDiagramms, Data.DBXJSONReflect ; type TmsIvalidatorParent = TmsCustomDiagramms; {$Include msIvalidator.mixin.pas} TmsDiagramms = class(TmsIvalidator) private [JSONMarshalled(True)] f_CurrentDiagramm : Integer; [JSONMarshalled(False)] f_Image: TPaintBox; function pm_GetCurrentDiagramm: TmsDiagramm; procedure DoInvalidateDiagramm(aDiagramm: TmsDiagramm); override; public constructor Create(anImage: TPaintBox; aList: TStrings); procedure ProcessClick(const aStart: TPointF); procedure Clear; procedure SelectShape(aList: TStrings; anIndex: Integer); procedure AllowedShapesToList(aList: TStrings); procedure AddDiagramm(aList: TStrings); function CurrentDiagrammIndex: Integer; procedure SelectDiagramm(anIndex: Integer); function CurrentShapeClassIndex: Integer; procedure Serialize; procedure DeSerialize; property CurrentDiagramm: TmsDiagramm read pm_GetCurrentDiagramm; procedure Assign(anOther: TmsDiagramms); end;//TmsDiagramms implementation uses {$Include msIvalidator.mixin.pas} System.SysUtils, FMX.Graphics, System.UITypes, msDiagrammsMarshal, msRegisteredShapes, msInvalidators ; {$Include msIvalidator.mixin.pas} // TmsDiagramms constructor TmsDiagramms.Create(anImage: TPaintBox; aList: TStrings); begin inherited Create; f_Image := anImage; AddDiagramm(aList); end; function TmsDiagramms.pm_GetCurrentDiagramm: TmsDiagramm; begin Result := Items[f_CurrentDiagramm].toObject As TmsDiagramm; end; procedure TmsDiagramms.DoInvalidateDiagramm(aDiagramm: TmsDiagramm); var l_Canvas : TCanvas; begin if (f_Image <> nil) then if (aDiagramm = CurrentDiagramm) then f_Image.Repaint; end; procedure TmsDiagramms.AddDiagramm(aList: TStrings); var l_D : ImsDiagramm; begin l_D := TmsDiagramm.Create('Диаграмма №' + IntToStr(Items.Count + 1)); Items.Add(l_D); f_CurrentDiagramm := Items.IndexOf(l_D); if (aList <> nil) then aList.Add(l_D.Name); end; function TmsDiagramms.CurrentDiagrammIndex: Integer; begin Result := f_CurrentDiagramm; end; procedure TmsDiagramms.SelectDiagramm(anIndex: Integer); begin if (anIndex < 0) OR (anIndex >= Items.Count) then Exit; f_CurrentDiagramm := anIndex; CurrentDiagramm.Invalidate; end; const c_FileName = 'All.json'; procedure TmsDiagramms.DeSerialize; begin TmsDiagrammsMarshal.DeSerialize(c_FileName, self); end; procedure TmsDiagramms.Assign(anOther: TmsDiagramms); var l_D : ImsDiagramm; begin inherited Assign(anOther); for l_D in Items do begin (l_D.toObject As TmsDiagramm).CurrentClass := TmsRegisteredShapes.Instance.First; end;//for l_D Self.f_CurrentDiagramm := anOther.CurrentDiagrammIndex; CurrentDiagramm.Invalidate; end; procedure TmsDiagramms.ProcessClick(const aStart: TPointF); begin CurrentDiagramm.ProcessClick(aStart); end; procedure TmsDiagramms.Clear; begin CurrentDiagramm.Clear; end; procedure TmsDiagramms.SelectShape(aList: TStrings; anIndex: Integer); begin CurrentDiagramm.SelectShape(aList, anIndex); end; procedure TmsDiagramms.Serialize; begin TmsDiagrammsMarshal.Serialize(c_FileName, self); end; procedure TmsDiagramms.AllowedShapesToList(aList: TStrings); begin CurrentDiagramm.AllowedShapesToList(aList); end; function TmsDiagramms.CurrentShapeClassIndex: Integer; begin Result := CurrentDiagramm.CurrentShapeClassIndex; end; end.
"Почувствуйте разницу", что называется.
Мало кому понравится.
Я знаю.
среда, 10 декабря 2014 г.
Коротко. MindStream. Как мы пишем ПО под FireMonkey. Часть 4 Serialization
http://habrahabr.ru/post/245441/
Ещё надо будет написать про расход памяти и производительность.
И провести соответствующие тесты.
Ещё надо будет написать про расход памяти и производительность.
И провести соответствующие тесты.
Коротко. Про TDD и "догматику". Только код
Коротко. Про TDD и "догматику". Только код.
По мне надо делать то, что "эффективно", а не то, что "догматично".
https://bitbucket.org/ingword/mindstream/src/027273a583c70d3ba588b056cb2a5cd4c9dd8014/Tests/Module/TestmsSerializeController.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/027273a583c70d3ba588b056cb2a5cd4c9dd8014/Tests/Module/msParametrizedShapeTestSuite.pas?at=MS-7_Lulin_Upgrade
procedure TmsShapeTestPrim.DeserializeDiargammAndCheck(aCheck: TmsDiagrammCheck; aShapeClass: RmsShape); begin CreateDiagrammAndCheck( procedure (const aDiagramm : ImsDiagramm) begin TmsDiagrammMarshal.DeSerialize(MakeFileName(TestSerializeMethodName, aShapeClass), aDiagramm.toObject As TmsDiagramm); // - берём результаты от ПРЕДЫДУЩИХ тестов, НЕКОШЕРНО с точки зрения TDD // НО! Чертовски эффективно. aCheck(aDiagramm); end , '' ); end; ... procedure TmsDiagrammTest.TestDeSerialize; var l_Diagramms : TmsDiagramms; l_FileName : String; begin l_Diagramms := TmsDiagramms.Create(nil, nil); try TmsDiagrammsMarshal.DeSerialize(MakeFileName(TestSerializeMethodName, f_Context.rShapeClass), l_Diagramms); // - берём результаты от ПРЕДЫДУЩИХ тестов, НЕКОШЕРНО с точки зрения TDD // НО! Чертовски эффективно. l_FileName := TestResultsFileName(f_Context.rShapeClass); TmsDiagrammsMarshal.Serialize(l_FileName, l_Diagramms); CheckFileWithEtalon(l_FileName); finally FreeAndNil(l_Diagramms); end;//try..finally end;
По мне надо делать то, что "эффективно", а не то, что "догматично".
https://bitbucket.org/ingword/mindstream/src/027273a583c70d3ba588b056cb2a5cd4c9dd8014/Tests/Module/TestmsSerializeController.pas?at=MS-7_Lulin_Upgrade
https://bitbucket.org/ingword/mindstream/src/027273a583c70d3ba588b056cb2a5cd4c9dd8014/Tests/Module/msParametrizedShapeTestSuite.pas?at=MS-7_Lulin_Upgrade
вторник, 9 декабря 2014 г.
Коротко. Про афинные преобразования. Только код
Коротко. Про афинные преобразования. Только код
https://bitbucket.org/ingword/mindstream/src/e0239b6d47ed4a74d4095731b3180e576ad5f5fa/ConcreteShapes/msLineWithArrow.pas?at=MS-7_Lulin_Upgrade
Было:
А правильно так:
Что изменилось?
Обратная матрица.
"Квадратная матрица обратима тогда и только тогда, когда она невырожденная, то есть её определитель не равен нулю. Для неквадратных матриц и вырожденных матриц обратных матриц не существует. Однако возможно обобщить это понятие и ввести псевдообратные матрицы, похожие на обратные по многим свойствам."
Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать.
Делайте выводы.
P.S. l_OriginalMatrix * l_OriginalMatrix.Inverse == TMatrix.Identity ;-)
Единичная матрица.
P.S.S. Итоговый код:
Из этого делаем простой вывод.
Что перемножение матриц - НЕ коммутативно.
Что и "логично" - A * B != B * A.
https://bitbucket.org/ingword/mindstream/src/e0239b6d47ed4a74d4095731b3180e576ad5f5fa/ConcreteShapes/msLineWithArrow.pas?at=MS-7_Lulin_Upgrade
Было:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext); var l_Proxy : TmsShape; l_OriginalMatrix: TMatrix; l_Matrix: TMatrix; l_Angle : Single; l_CenterPoint : TPointF; l_TextRect : TRectF; begin inherited; if (StartPoint <> FinishPoint) then begin l_OriginalMatrix := aCtx.rCanvas.Matrix; try l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint); try // in Radian l_Angle := GetArrowAngleRotation; // create a point around which will rotate l_CenterPoint := TPointF.Create(FinishPoint.X, FinishPoint.Y); l_Matrix := l_OriginalMatrix; l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y); l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle); l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y); aCtx.rCanvas.SetMatrix(l_Matrix); l_Proxy.DrawTo(aCtx); finally FreeAndNil(l_Proxy); end;//try..finally finally aCtx.rCanvas.SetMatrix(l_OriginalMatrix); end; end;//(StartPoint <> FinishPoint) end;
А правильно так:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext); var l_Proxy : TmsShape; l_OriginalMatrix: TMatrix; l_Matrix: TMatrix; l_Angle : Single; l_CenterPoint : TPointF; l_TextRect : TRectF; begin inherited; if (StartPoint <> FinishPoint) then begin l_OriginalMatrix := aCtx.rCanvas.Matrix; try l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint); try // in Radian l_Angle := GetArrowAngleRotation; // create a point around which will rotate l_CenterPoint := TPointF.Create(FinishPoint.X, FinishPoint.Y); l_Matrix := l_OriginalMatrix * l_OriginalMatrix.Inverse; l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y); l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle); l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y); l_Matrix := l_Matrix * l_OriginalMatrix; aCtx.rCanvas.SetMatrix(l_Matrix); l_Proxy.DrawTo(aCtx); finally FreeAndNil(l_Proxy); end;//try..finally finally aCtx.rCanvas.SetMatrix(l_OriginalMatrix); end; end;//(StartPoint <> FinishPoint) end;
Что изменилось?
l_Matrix := l_OriginalMatrix * l_OriginalMatrix.Inverse; // - СНИМАЕМ оригинальную матрицу
Обратная матрица.
"Квадратная матрица обратима тогда и только тогда, когда она невырожденная, то есть её определитель не равен нулю. Для неквадратных матриц и вырожденных матриц обратных матриц не существует. Однако возможно обобщить это понятие и ввести псевдообратные матрицы, похожие на обратные по многим свойствам."
l_Matrix := l_Matrix * l_OriginalMatrix; // - ПРИМЕНЯЕМ оригинальную матрицу
Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать.
Делайте выводы.
P.S. l_OriginalMatrix * l_OriginalMatrix.Inverse == TMatrix.Identity ;-)
Единичная матрица.
P.S.S. Итоговый код:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext); var l_Proxy : TmsShape; l_OriginalMatrix: TMatrix; l_Matrix: TMatrix; l_Angle : Single; l_CenterPoint : TPointF; l_TextRect : TRectF; begin inherited; if (StartPoint <> FinishPoint) then begin l_OriginalMatrix := aCtx.rCanvas.Matrix; try l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint); try // in Radian l_Angle := GetArrowAngleRotation; l_CenterPoint := FinishPoint; l_Matrix := TMatrix.Identity; // - СНИМАЕМ оригинальную матрицу, точнее берём ЕДИНИЧНУЮ матрицу // https://ru.wikipedia.org/wiki/%D0%95%D0%B4%D0%B8%D0%BD%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D0%B0 l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y); // - задаём точку, вокруг которой вертим l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle); // - задаём угол поворота l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y); // - задаём начало координат l_Matrix := l_Matrix * l_OriginalMatrix; // - ПРИМЕНЯЕМ оригинальную матрицу // Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать. // https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BF%D0%B5%D1%80%D0%B5%D0%BD%D0%BE%D1%81 aCtx.rCanvas.SetMatrix(l_Matrix); // - применяем нашу "комплексную" матрицу l_Proxy.DrawTo(aCtx); // - отрисовываем примитив с учётом матрицы преобразований finally FreeAndNil(l_Proxy); end;//try..finally finally aCtx.rCanvas.SetMatrix(l_OriginalMatrix); // - восстанавливаем ОРИГИНАЛЬНУЮ матрицу end;//try..finally end;//(StartPoint <> FinishPoint) end;
Из этого делаем простой вывод.
Что перемножение матриц - НЕ коммутативно.
Что и "логично" - A * B != B * A.
- Умножение матриц некоммутативно:
- , но
понедельник, 8 декабря 2014 г.
И ещё про "примеси". Только код
По мотивам:
Про "примеси", шаблоны и Generic'и №3
И ещё раз про "примеси". Теперь - "серьёзно"
Коротко. Контроль за созданием/освобождением объектов. Только код. №4
Теперь вот какая штука.
Есть:
TmsDiagramms - это список TmsDiagramm.
TmsDiagramm - это список TmsShape.
Явно - "рекурсивное решение".
Как это обобщить?
Ну примерно так:
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/?at=MS-6_AddTestToMindStream
TmsItemsHolder.mixin.pas:
msDiagramm.pas:
msDiagramms.pas:
Ну и сериализация:
TmsMarshal.mixin.pas:
Ну и тесты:
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/?at=MS-6_AddTestToMindStream
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/TestmsSerializeController.pas?at=MS-6_AddTestToMindStream
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/msParametrizedShapeTestSuite.pas?at=MS-6_AddTestToMindStream
Вряд ли кому-то понравится. Я знаю.
Про "примеси", шаблоны и Generic'и №3
И ещё раз про "примеси". Теперь - "серьёзно"
Коротко. Контроль за созданием/освобождением объектов. Только код. №4
Теперь вот какая штука.
Есть:
TmsDiagramms - это список TmsDiagramm.
TmsDiagramm - это список TmsShape.
Явно - "рекурсивное решение".
Как это обобщить?
Ну примерно так:
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/?at=MS-6_AddTestToMindStream
TmsItemsHolder.mixin.pas:
{$IfNDef TmsItemsHolder_uses_intf} // Объект содержащий список других объектов // interface {$Define TmsItemsHolder_uses_intf} // uses Generics.Collections, Data.DBXJSONReflect, System.Rtti {$Else TmsItemsHolder_uses_intf} {$IfNDef TmsItemsHolder_intf} // http://programmingmindstream.blogspot.ru/2014/12/generic-2.html {$Define TmsItemsHolder_intf} TmsRttiFieldLambda = reference to procedure (aField: TRttiField); TmsItemsList = TList<TmsItem>; TmsItemsHolder = class(TmsItemsHolderParent) private [JSONMarshalled(True)] f_Items : TmsItemsList; function pm_GetItems: TmsItemsList; procedure pm_SetItems(aValue: TmsItemsList); class procedure RegisterItemsLike(aLambda: TmsRttiFieldLambda); public constructor Create; destructor Destroy; override; property Items: TmsItemsList read pm_GetItems write pm_SetItems; procedure Assign(anOther : TmsItemsHolder); class procedure RegisterInMarshal(aMarshal: TJSONMarshal); class procedure RegisterInUnMarshal(aMarshal: TJSONUnMarshal); end;//TmsItemsHolder {$Else TmsItemsHolder_intf} // implementation {$IfNDef TmsItemsHolder_uses_impl} // uses System.TypInfo {$Define TmsItemsHolder_uses_impl} {$Else TmsItemsHolder_uses_impl} // TmsItemsHolder constructor TmsItemsHolder.Create; begin inherited; Assert(f_Items = nil); f_Items := TmsItemsList.Create; end; destructor TmsItemsHolder.Destroy; begin FreeAndNil(f_Items); inherited; end; function TmsItemsHolder.pm_GetItems: TmsItemsList; begin if (f_Items = nil) then f_Items := TmsItemsList.Create; Result := f_Items; end; procedure TmsItemsHolder.pm_SetItems(aValue: TmsItemsList); var l_Item : TmsItem; begin if (f_Items <> nil) then f_Items.Clear; if (aValue <> nil) then for l_Item in aValue do begin if (f_Items = nil) then f_Items := TmsItemsList.Create; f_Items.Add(l_Item); end;//for l_Shape in aValue end; procedure TmsItemsHolder.Assign(anOther : TmsItemsHolder); begin Self.Items := anOther.Items; end; class procedure TmsItemsHolder.RegisterItemsLike(aLambda: TmsRttiFieldLambda); var l_Field : TRttiField; begin for l_Field in TRttiContext.Create.GetType(Self).GetFields do if (l_Field.Visibility = mvPrivate) then if (l_Field.Name = 'f_Items') then begin aLambda(l_Field); Exit; end;//l_Field.Name = 'f_Items' Assert(false, 'Не найдено поля для Items'); end; class procedure TmsItemsHolder.RegisterInMarshal(aMarshal: TJSONMarshal); begin RegisterItemsLike( procedure (aField: TRttiField) var l_FieldName : String; begin l_FieldName := aField.Name; aMarshal.RegisterConverter(Self, l_FieldName, function (Data: TObject; Field: String): TListOfObjects var l_Item: TmsItem; l_Index: Integer; begin Assert(Field = l_FieldName); SetLength(Result, (Data As TmsItemsHolder).Items.Count); l_Index := 0; for l_Item in (Data As TmsItemsHolder).Items do begin Result[l_Index] := l_Item.toObject; Inc(l_Index); end;//for l_Item end );//aMarshal.RegisterConverter end );//RegisterItemsLike end; class procedure TmsItemsHolder.RegisterInUnMarshal(aMarshal: TJSONUnMarshal); begin RegisterItemsLike( procedure (aField: TRttiField) var l_FieldName : String; begin l_FieldName := aField.Name; aMarshal.RegisterReverter(Self, l_FieldName, procedure (Data: TObject; Field: String; Args: TListOfObjects) var l_Object: TObject; l_Holder : TmsItemsHolder; l_ItemI : TmsItem; begin Assert(Field = l_FieldName); l_Holder := Data As TmsItemsHolder; Assert(l_Holder <> nil); for l_Object in Args do begin if Supports(l_Object, TmsItem, l_ItemI) then l_Holder.Items.Add(l_ItemI) else raise Exception.Create(l_Object.ClassName + ' не поддерживает нужный интерфейс'); end//for l_Object end );//aMarshal.RegisterReverter end );//RegisterItemsLike end; {$EndIf TmsItemsHolder_uses_impl} {$EndIf TmsItemsHolder_intf} {$EndIf TmsItemsHolder_uses_intf}
msDiagramm.pas:
unit msDiagramm; interface uses {$Include msItemsHolder.mixin.pas} , FMX.Graphics, System.SysUtils, System.Types, System.UITypes, msShape, msPointCircle, System.Classes, FMX.Objects, msRegisteredShapes, FMX.Dialogs, System.JSON, msCoreObjects, msSerializeInterfaces, msInterfacedNonRefcounted, msInterfacedRefcounted ; type ImsDiagramm = interface ['{59F2D068-F06F-4378-9ED4-888DFE8DFAF2}'] function toObject: TObject; function Get_Name: String; property Name: String read Get_Name; end;//ImsDiagramm TmsItemsHolderParent = TmsInterfacedRefcounted{TmsInterfacedNonRefcounted}; TmsItem = ImsShape; {$Include msItemsHolder.mixin.pas} TmsDiagramm = class(TmsItemsHolder, ImsDiagramm, ImsShapeByPt, ImsShapesController) // - Выделяем интерфейс ImsObjectWrap. // Смешно - если TmsDiagramm его реализет НАПРЯМУЮ, то всё хорошо. // А если через ImsSerializable, то - AV. // Про это можно писать отдельную статью. private [JSONMarshalled(False)] FCurrentClass: RmsShape; [JSONMarshalled(False)] FCurrentAddedShape: ImsShape; [JSONMarshalled(False)] FCanvas: TCanvas; [JSONMarshalled(True)] fName: String; private procedure DrawTo(const aCanvas: TCanvas); function CurrentAddedShape: ImsShape; procedure BeginShape(const aStart: TPointF); procedure EndShape(const aFinish: TPointF); function ShapeIsEnded: Boolean; class function AllowedShapes: TmsRegisteredShapes; procedure CanvasChanged(aCanvas: TCanvas); function ShapeByPt(const aPoint: TPointF): ImsShape; procedure RemoveShape(const aShape: ImsShape); function Get_Name: String; constructor CreatePrim(anImage: TImage; const aName: String); public class function Create(anImage: TImage; const aName: String): ImsDiagramm; procedure ResizeTo(anImage: TImage); procedure ProcessClick(const aStart: TPointF); procedure Clear; procedure Invalidate; procedure AllowedShapesToList(aList: TStrings); procedure SelectShape(aList: TStrings; anIndex: Integer); property Name: String read fName write fName; function CurrentShapeClassIndex: Integer; procedure Serialize; procedure DeSerialize; procedure Assign(const anOther : TmsDiagramm); property CurrentClass: RmsShape read FCurrentClass write FCurrentClass; end;//TmsDiagramm implementation uses {$Include msItemsHolder.mixin.pas} , msMover, msCircle, msDiagrammMarshal ; {$Include msItemsHolder.mixin.pas} const c_FileName = '.json'; class function TmsDiagramm.AllowedShapes: TmsRegisteredShapes; begin Result := TmsRegisteredShapes.Instance; end; procedure TmsDiagramm.AllowedShapesToList(aList: TStrings); var l_Class: RmsShape; begin aList.Clear; for l_Class in AllowedShapes do if l_Class.IsForToolbar then aList.AddObject(l_Class.ClassName, TObject(l_Class)); end; function TmsDiagramm.CurrentShapeClassIndex: Integer; begin Result := AllowedShapes.IndexOf(FCurrentClass); end; procedure TmsDiagramm.SelectShape(aList: TStrings; anIndex: Integer); begin if (anIndex < 0) then CurrentClass := TmsRegisteredShapes.Instance.First else CurrentClass := RmsShape(aList.Objects[anIndex]); end; procedure TmsDiagramm.Serialize; begin TmsDiagrammMarshal.Serialize(Self.Name + c_FileName, self); end; procedure TmsDiagramm.ProcessClick(const aStart: TPointF); begin if ShapeIsEnded then // - мы НЕ ДОБАВЛЯЛИ примитива - надо его ДОБАВИТЬ BeginShape(aStart) else EndShape(aStart); end; procedure TmsDiagramm.BeginShape(const aStart: TPointF); begin assert(CurrentClass <> nil); FCurrentAddedShape := CurrentClass.Create(TmsMakeShapeContext.Create(aStart, Self)); if (FCurrentAddedShape <> nil) then begin Items.Add(FCurrentAddedShape); if not FCurrentAddedShape.IsNeedsSecondClick then // - если не надо SecondClick, то наш примитив - завершён FCurrentAddedShape := nil; Invalidate; end; // FCurrentAddedShape <> nil end; procedure TmsDiagramm.Clear; begin if (f_Items <> nil) then f_Items.Clear; Invalidate; end; class function TmsDiagramm.Create(anImage: TImage; const aName: String): ImsDiagramm; begin Result := CreatePrim(anImage, aName); end; constructor TmsDiagramm.CreatePrim(anImage: TImage; const aName: String); begin inherited Create; FCurrentAddedShape := nil; FCanvas := nil; ResizeTo(anImage); FCurrentClass := AllowedShapes.First; fName := aName; end; function TmsDiagramm.Get_Name: String; begin Result := FName; end; procedure TmsDiagramm.ResizeTo(anImage: TImage); begin if (anImage <> nil) then begin anImage.Bitmap := TBitmap.Create(Round(anImage.Width), Round(anImage.Height)); CanvasChanged(anImage.Bitmap.Canvas); end;//anImage <> nil end; procedure TmsDiagramm.CanvasChanged(aCanvas: TCanvas); begin FCanvas := aCanvas; Invalidate; end; function TmsDiagramm.CurrentAddedShape: ImsShape; begin Result := FCurrentAddedShape; end; procedure TmsDiagramm.Assign(const anOther : TmsDiagramm); begin inherited Assign(anOther); Self.Name := anOther.Name; Self.Invalidate; end; procedure TmsDiagramm.DeSerialize; begin Clear; try TmsDiagrammMarshal.DeSerialize(Self.Name + c_FileName, Self); except on EFOpenError do Exit; end;//try..except end; procedure TmsDiagramm.DrawTo(const aCanvas: TCanvas); var l_Shape: ImsShape; begin aCanvas.BeginScene; try Assert(f_Items <> nil); for l_Shape in f_Items do l_Shape.DrawTo(TmsDrawContext.Create(aCanvas)); finally aCanvas.EndScene; end; // try..finally end; procedure TmsDiagramm.EndShape(const aFinish: TPointF); begin assert(CurrentAddedShape <> nil); CurrentAddedShape.EndTo(TmsEndShapeContext.Create(aFinish, Self)); FCurrentAddedShape := nil; Invalidate; end; procedure TmsDiagramm.Invalidate; begin if (FCanvas <> nil) then begin FCanvas.BeginScene; try FCanvas.Clear(TAlphaColorRec.Null); DrawTo(FCanvas); finally FCanvas.EndScene; end;//try..finally end;//FCanvas <> nil end; function TmsDiagramm.ShapeIsEnded: Boolean; begin Result := (CurrentAddedShape = nil); end; function TmsDiagramm.ShapeByPt(const aPoint: TPointF): ImsShape; var l_Shape: ImsShape; l_Index: Integer; begin Result := nil; for l_Index := f_Items.Count - 1 downto 0 do begin l_Shape := f_Items.Items[l_Index]; if l_Shape.ContainsPt(aPoint) then begin Result := l_Shape; Exit; end; // l_Shape.ContainsPt(aPoint) end; // for l_Index end; procedure TmsDiagramm.RemoveShape(const aShape: ImsShape); begin Assert(f_Items <> nil); f_Items.Remove(aShape); end; end.
msDiagramms.pas:
unit msDiagramms; interface uses {$Include msItemsHolder.mixin.pas} , msDiagramm, System.Types, FMX.Objects, System.Classes, msCoreObjects, msWatchedObjectInstance ; type TmsItemsHolderParent = TmsWatchedObject; TmsItem = ImsDiagramm; {$Include msItemsHolder.mixin.pas} TmsDiagramms = class(TmsItemsHolder) private [JSONMarshalled(True)] f_CurrentDiagramm : Integer; [JSONMarshalled(False)] f_Image: TImage; function pm_GetCurrentDiagramm: TmsDiagramm; public constructor Create(anImage: TImage; aList: TStrings); procedure ProcessClick(const aStart: TPointF); procedure Clear; procedure SelectShape(aList: TStrings; anIndex: Integer); procedure AllowedShapesToList(aList: TStrings); procedure ResizeTo(anImage: TImage); procedure AddDiagramm(anImage: TImage; aList: TStrings); function CurrentDiagrammIndex: Integer; procedure SelectDiagramm(anIndex: Integer); function CurrentShapeClassIndex: Integer; procedure Serialize; procedure DeSerialize; property CurrentDiagramm: TmsDiagramm read pm_GetCurrentDiagramm; procedure Assign(anOther: TmsDiagramms); end;//TmsDiagramms implementation uses {$Include msItemsHolder.mixin.pas} , System.SysUtils, msDiagrammsMarshal, msRegisteredShapes ; {$Include msItemsHolder.mixin.pas} // TmsDiagramms constructor TmsDiagramms.Create(anImage: TImage; aList: TStrings); begin inherited Create; f_Image := anImage; AddDiagramm(anImage, aList); end; function TmsDiagramms.pm_GetCurrentDiagramm: TmsDiagramm; begin Result := Items[f_CurrentDiagramm].toObject As TmsDiagramm; end; procedure TmsDiagramms.AddDiagramm(anImage: TImage; aList: TStrings); var l_D : ImsDiagramm; begin l_D := TmsDiagramm.Create(anImage, 'Диаграмма №' + IntToStr(Items.Count + 1)); Items.Add(l_D); f_CurrentDiagramm := Items.IndexOf(l_D); if (aList <> nil) then aList.Add(l_D.Name); // aList.AddObject(l_D.Name, TObject(f_CurrentDiagramm)); end; function TmsDiagramms.CurrentDiagrammIndex: Integer; begin Result := f_CurrentDiagramm; end; procedure TmsDiagramms.SelectDiagramm(anIndex: Integer); begin if (anIndex < 0) OR (anIndex >= Items.Count) then Exit; f_CurrentDiagramm := anIndex; CurrentDiagramm.Invalidate; end; const c_FileName = 'All.json'; procedure TmsDiagramms.DeSerialize; begin TmsDiagrammsMarshal.DeSerialize(c_FileName, self); // CurrentDiagramm.DeSerialize; end; procedure TmsDiagramms.Assign(anOther: TmsDiagramms); var l_D : ImsDiagramm; begin inherited Assign(anOther); for l_D in Items do begin (l_D.toObject As TmsDiagramm).ResizeTo(f_Image); (l_D.toObject As TmsDiagramm).CurrentClass := TmsRegisteredShapes.Instance.First; end;//for l_D Self.f_CurrentDiagramm := anOther.CurrentDiagrammIndex; CurrentDiagramm.Invalidate; end; procedure TmsDiagramms.ProcessClick(const aStart: TPointF); begin CurrentDiagramm.ProcessClick(aStart); end; procedure TmsDiagramms.Clear; begin CurrentDiagramm.Clear; end; procedure TmsDiagramms.SelectShape(aList: TStrings; anIndex: Integer); begin CurrentDiagramm.SelectShape(aList, anIndex); end; procedure TmsDiagramms.Serialize; begin TmsDiagrammsMarshal.Serialize(c_FileName, self); // CurrentDiagramm.Serialize; end; procedure TmsDiagramms.AllowedShapesToList(aList: TStrings); begin CurrentDiagramm.AllowedShapesToList(aList); end; procedure TmsDiagramms.ResizeTo(anImage: TImage); begin CurrentDiagramm.ResizeTo(anImage); end; function TmsDiagramms.CurrentShapeClassIndex: Integer; begin Result := CurrentDiagramm.CurrentShapeClassIndex; end; end.
Ну и сериализация:
TmsMarshal.mixin.pas:
{$IfNDef TmsMarshal_uses_intf} // interface {$Define TmsMarshal_uses_intf} // uses JSON, Data.DBXJSONReflect, msMarshalPrim {$Else TmsMarshal_uses_intf} {$IfNDef TmsMarshal} // http://programmingmindstream.blogspot.ru/2014/12/generic-2.html {$Define TmsMarshal} TmsMarshal = class(TmsMarshalPrim) // - шаблонизируем, ибо мы скоро будем сериализовать и другие классы. public class procedure Serialize(const aFileName: string; const aDiagramm: TClassToSerialize); class procedure DeSerialize(const aFileName: string; const aDiagramm: TClassToSerialize); end;//TmsMarshal {$Else TmsMarshal} // implementation {$IfNDef TmsMarshal_uses_impl} // uses SysUtils, msCoreObjects, msStringList {$Define TmsMarshal_uses_impl} {$Else TmsMarshal_uses_impl} // TmsMarshal class procedure TmsMarshal.DeSerialize(const aFileName: string; const aDiagramm: TClassToSerialize); var l_StringList: TmsStringList; l_D : TClassToSerialize; begin l_StringList := TmsStringList.Create; try l_StringList.LoadFromFile(aFileName); l_D := UnMarshal.Unmarshal(TJSONObject.ParseJSONValue(l_StringList.Text)) As TClassToSerialize; try aDiagramm.Assign(l_D); finally FreeAndNil(l_D); end;//try..finally finally FreeAndNil(l_StringList); end;//try..finally end; class procedure TmsMarshal.Serialize(const aFileName: string; const aDiagramm: TClassToSerialize); var l_Json: TJSONObject; l_StringList: TmsStringList; begin l_StringList := TmsStringList.Create; try l_Json := nil; try l_Json := Marshal.Marshal(aDiagramm) as TJSONObject; l_StringList.Add(l_Json.toString); finally FreeAndNil(l_Json); end;//try..finally l_StringList.SaveToFile(aFileName); finally FreeAndNil(l_StringList); end;//try..finally end; {$EndIf TmsMarshal_uses_impl} {$EndIf TmsMarshal} {$EndIf TmsMarshal_uses_intf}
Ну и тесты:
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/?at=MS-6_AddTestToMindStream
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/TestmsSerializeController.pas?at=MS-6_AddTestToMindStream
https://bitbucket.org/ingword/mindstream/src/18a744357c57406fc89a5e5498d01394abe6cb4c/Tests/Module/msParametrizedShapeTestSuite.pas?at=MS-6_AddTestToMindStream
Вряд ли кому-то понравится. Я знаю.