вторник, 31 июля 2007 г.

Система: MorphX, среда разработки

[id:034]

Полное имя — MorphX Development Suite.
Так называется среда разработки в Axapta, или по ненашему — Integrated Development Environment (IDE).

Все, что связано с проектированием форм и отчетов, редактированием компилированием и отладкой кода, все это — MorphX.

Выбери класс AddressSelectForm_PurchLine IDE интегрирована с самой системой. Что представляет из себя редактор X++ кода? Откройте AOT и два раза щелкните на имени класса "AddressSelectForm_PurchLine".

Увидите окно редактора X++: Окно редактора кода Вот он какой северный олень. В панели слева отображается список всех методов класса «AddressSelectForm_PurchLine»; содержимое выделенного метода показывается справа. У любого класса присутствует строка "classDeclaration" в левой панели. Это не метод; в нем выводится объявление класса (как называется класс, от кого наследуется) и объявление его полей. Переходить по отображенным методам редактора можно с помощью комбинации Ctrl+Tab и Ctrl+Shift+Tab.

По началу такое представление было очень непривычным. Привык видеть все методы внутри класса, как в .NET. Но куда денешься?! Замечу на будущее: я буду приводить примеры кода классов в манере .NET, не вынося тело каждого метода за границы класса.

Итог

  • нужно привыкнуть к редактору кода
  • Ctrl+Tab — для перехода по методам на левой панели редактора.

четверг, 26 июля 2007 г.

Пожиратель огурцов

Рабочие места на моей работе сделаны на американский манер — перегородки, отделяющие столы, и это все — в большой комнате.

За перегородкой сидит парень деревенской наружности, 185 сантиметров по вертикали и... ЖРЕТ ОГУРЦЫ в течение последних СТА МИНУТ!!! Хруст начал добивать. Под конец огуречного марафона возникло стойкое ощущение, что я объелся огурцов, во рту появился специфический привкус огурцовой кожуры, темно-зеленой такой.

1 кг огурцов дают организму 150 килокалорий. За два часа можно перемолоть не менее килограмма. Таким образом, ртом он добыл 150 килокалорий и набил свой желудок.
Коню-соседу нужно около 3000 килокалорий в день, чтобы жить. Если грубо поделить эти три тысячи на 24 часа, что есть в нашем распоряжении каждый день, получается - 125 килокалорий в час необходимо засовывать в организм. За два часа - 250 килокалорий, которые нужно как-то восполнить.
Потери энергии: 250 (килокалорий, которые нужны нашему коню за прошелшие два часа) - 150 (килокалорий, что он выжал из огурцов за теже два часа) = 100 килокалорий

Хочет похудеть!
Бегай, жиробас!
Ах, бег тебе противопоказан?
И ты бегал раньше, но не помогло?

Я бегал по утрам - ни одного жирного не видел, все вокруг были поджарые. Какие еще отговорки будут?

среда, 25 июля 2007 г.

X++: наследование 1

[id:029]

Наследовать класс можно только от одного класса.

Создаем класс BLG29_ClassBase с конструктором: class BLG29_ClassBase { int iMyVar; void new() { iMyVar = 123; print 'constructor of base class'; } }

Создаем дочерний класс BLG29_ClassChild, туда же помести метод main(). Внимание на слово "extends": class BLG29_ClassChild extends BLG29_ClassBase { // конструктор класса void new() { super(); print 'constructor of inherited class'; } int getMyVar() { return iMyVar; } static void main(Args _args) { BLG29_ClassChild cls; cls = new BLG29_ClassChild(); print cls.getMyVar(); pause; } }

У меня появилось: Результат. Родительский класс тоже отработал

Слово "super" в конструкторе класса BLG29_ClassChild вызывает конструктор родительского класса BLG29_ClassBase.
Конструктор класса BLG29_ClassBase не запускается автоматически, попробуй закомментировать строку с вызовом super() в конструкторе класса BLG29_ClassChild.
Получишь: Результат отключения вызова родительского конструктора

Итог
  • наследование задается с помощью слова «extends»;
  • наследовать можно только от одного класса;
  • модификаторы доступа (public, protected, private) при наследовании не задаются (как в .NET);
  • доступ к перегруженным методам базового класса из дочернего — через волшебное слово "super";

X++: абстрактный класс

[id:032]

Создаем абстрактный класс и метод в нем (внимание на ключевое слово "abstract"): abstract class BLG32_AbstractClass { int iMyVar; int MyMethod() { return iMyVar + 100; } }

Еще класс с методом main(): class BLG32_Class { static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_AbstractClass(); } }

Что получил? Ошибка компиляции. На то он и абстрактный, что нельзя создать объект этого класса.
Исправляем ошибку. Для этого сделаем класс BLG32_Class наследником от BLG32_AbstractClass и будет обращаться к реальному классу, а не какой-то там абстракции: class BLG32_Class extends BLG32_AbstractClass { static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_Class(); print cls.MyMethod(); pause; } }

Я увидел цифру 100. А ведь мы даже не переопределяли метод MyMethod() в классе BLG32_Class! А все потому, что MyMethod() вполне реальный метод, несмотря на то, что класс, где он размещен, абстрактный.
Экспериментируем дальше, сделай метод MyMethod() абстрактным: abstract class BLG32_AbstractClass { int iMyVar; abstract int MyMethod() { // Абстрактный метод должен быть пустым, иначе - заругають! //return iMyVar + 100; } }

Заметь, я отчистил тело метода.
А в классе BLG32_Class я переопределил метод: class BLG32_Class extends BLG32_AbstractClass { int MyMethod() { return iMyVar + 1000; } static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_Class(); print cls.MyMethod(); pause; } }

Результат: цифра 1000.

Итак:

  • в неабстрактный метод абстрактного класса можно что-нибудь написать
  • тело абстрактного метода должно быть пустым (как у интерфейса)
  • в отличие от наследования интерфейса, при наследовании от абстрактного класса начинает работать полезный пункт «Перекрыть метод». Попробуй:
    Переименуй метод MyMethod() во что-нибудь другое. Щелкни правой клавишей в окне проекта на классе BLG32_Class, пункт «Перекрыть метод» и тебе откроется список методов, доступных для перегрузки. Не правда ли, это хорошая возможность поберечь свои пальцы?

X++: объявление интерфейса

[id:027]

Интерфейс создается как и класс, в той же ветке — "Classes"; отличие в ключевом слове "interface".

Пишем. Создаем интерфейс "BLG27_MyInterface" и метод в нем: interface BLG27_MyInterface { void methodToImplement() { } }

Создайте класс "BLG27_Class" (внимание на слово "implements") и метод main() в нем: class BLG27_Class implements BLG27_MyInterface { static void main(Args _args) { BLG27_Class cls = new BLG27_Class(); cls.methodToImplement(); pause; } }

Компилируем и получаем ошибку «забыл реализовать метод methodToImplement()». Исправляем этот недочет, создайте метод на классе BLG27_Class: void methodToImplement() { print 'methodToImplement'; }

Запускайте. Увидите строку «methodToImplement».
Сохрани "BLG27_MyInterface", он еще понадобится.

Итог:

два ключевых слова для работы с интерфейсами — interface и implements.

X++: метод main()

[id:025]

Метод main() — это точка входа для класса. Если знаком с методом main() из мира C#, то здесь все точно также. Хотя он создается в рамках конкретного класса, метод нужно рассматривать, как нечто обособленное.

Выглядит следующим образом: static void main(Args _args) { // Здесь ваш код }
main() — статический метод. Обязательно присутствует параметр типа Args, в нем передаются возможные параметры. Параметры именно возможные, но не обязательные.

Попрактикуемся. Создайте класс: public class BLG25_Class { }

Чтобы запустить класс, нужно его открыть: щелкните правой кнопкой на классе в дереве проекта, пункт «Открыть». И ничего не произойдет Открываем класс

Создайте метод main() в классе BLG25_Class: public class BLG25_Class { static void main(Args _args) { ; info('Hello, world!'); } }
Теперь снова откройте класс. Появиться сообщение, замозолившее программисту глаза.

Итог

main — статический метод, играет роль точки входа на классе. Нужен, прежде всего, для целей тестирования.

X++: поля класса

[id:24]

Здесь и далее использую термин «поле класса» в том же значении, как это было в С++: это переменные, объявленные в классе (но не в его методах).

Пробуем создать поле.
Создаем класс BLG24_ClassBase и в нем объявляем поле iMyVar типа int и конструктор инициализации поля: class BLG24_ClassBase { int iMyVar; void new() { iMyVar = 123; } }

Создаем еще один класс "BLG24_ClassChild" и в нем определяем статический метод main(): class BLG24_ClassChild { static void main(Args _args) { BLG24_ClassBase cls; cls = new BLG24_ClassBase(); print cls.iMyVar; pause; } }

Компилируйте. Не получилось? Значит делаем вывод: доступ к полям класса BLG24_ClassBase «из вне» не возможен. Возьмите на заметку.

Делаем класс BLG24_ClassChild дочерним от BLG24_ClassBase с помощью ключевого слова "extends". Добавляем метод getMyVar(), чтобы получить значение поля и переписываем имеющийся метод main(): class BLG24_ClassChild extends BLG24_ClassBase { int getMyVar() { return iMyVar; } static void main(Args _args) { BLG24_ClassChild cls; cls = new BLG24_ClassChild(); print cls.getMyVar(); pause; } }

Запустите метод main(). Результат: Результат - получили значение поля базового класса

О наследовании классов расскажу позже.

Итог

поля класса видят только методы данного класса и его дочки. Всем остальным доступ закрыт