|  | 
|  06.08.2008, 18:24 | #1 | 
| Участник | MAP vs Class. В чем идейная необходимость в MAP-ах? А что если использовать Class вместо MAP? 
			
			MAP vs Class. В чем идейная необходимость в MAP-ах? А что если использовать Class вместо MAP?
		 | 
|  | 
|  06.08.2008, 19:48 | #2 | 
| Member | 
			
			А как вы в класс будете передавать буфер различных таблиц и там его обрабатывать?
		 
				__________________ С уважением, glibs® | 
|  | 
|  07.08.2008, 09:51 | #3 | 
| MCT | 
			
			Стот отметить, что Map в Axapt-e реализован как две сущности. Одна это класс коллекции, а другая это сущность в АОТ. Одна служит для обработки объектов в оперативной памяти, а вторая для удобства заполнения сущностей с одинаковым набором полей как то Поставщики-Клиенты. Класс - это некая структура (базовый кирпичик) для постоения модификаций. Если сравнивать первый Map и class, то здесь есть особенности того, что в мапе присуствует ключ и его можно использовать как некий упорядочный список. Он удобен для кэширования информации. Множественные ключи в нем могут прикрепляться к одному и тому же значению, но один ключ может прикрепляться только к одному значению за раз. Добавление пары ключа и значения в место, где ключ уже привязан к значению изменит связь так, что ключ будет привязан к новому значению. X++: Map map = new Map(Types::String, Types::Enum); Word wordType; ; map.insert("Car", Word::Noun); map.insert("Bike", Word::Noun); map.insert("Walk", Word::Verb); map.insert("Nice", Word::Adjective); print map.elements(); //4; wordType = map.lookup("Car"); print strfmt("Car is a %1", wordType); //Car is a Noun pause; | 
|  | 
|  07.08.2008, 10:00 | #4 | 
| Участник | |
|  | 
|  07.08.2008, 12:53 | #5 | 
| Member | Цитата: 
		
			Сообщение от Raven Melancholic
			
			 ...Ну... 
				__________________ С уважением, glibs® | 
|  | 
|  08.08.2008, 09:58 | #6 | 
| Участник | 
			
			Спасибо за комплимент но. к сожалению, не могу ни принять на свой счёт, ни вписать в резюме, так как автором иерархии классов, в основе которых лежит InventMovement я не являюсь. В использовании классов, наследников InventMovement есть ошибки, но внёс их не я. Есть документальные подтверждения, что как минимум один человек разбирался с классами из иерархии InventMovement (в инете есть статья от Fed), поэтому обобщение никому не подходит. Время очень жалко - этот ресурс невосполнимый. Но время, затраченное на разбор вызова, подобному: X++: movement = InventMovement::construct(salesLine, InventMovSubType::None, _childBuffer) estimated = InventUpd_Estimated::newInventMovement(movement); estimated.updateNow(); X++: this.LineAmount = this.lineAmountMST(this.Qty); X++: this.SalesPurchLine::lineAmountMST Еще мне жалко времени на то, что при загрузке проектов, полученных от аутсорсеров при наличии в них изменённых мапов я не могу выполнить сравнение из-за застарелой ошибки сравнения ветки Mappings. Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы. | 
|  | 
|  08.08.2008, 11:59 | #7 | 
| Участник | Цитата: 
		
			Сообщение от Raven Melancholic
			   Повторюсь, на перепрыгивание туда-сюда мне времени жалко, причем, в this.lineAmountMST(this.Qty) стандартная функция просмотра определения не работает (понятно почему). Еще мне жалко времени на то, что при загрузке проектов, полученных от аутсорсеров при наличии в них изменённых мапов я не могу выполнить сравнение из-за застарелой ошибки сравнения ветки Mappings. Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы. Так что здесь на одной чаше весов - удобное "перепрыгивание", а на другой: - быстродействие (мэппинг - это все таки "ядро", и этим НАДО пользоваться), - простота (трудозатраты на создание, расширение и поддержку мэппинга классами существенно больше), - шаблон (разработчики, как художники, непременно реализуют конкретный мэппинг каждый по-своему) Поэтому, я голосую за MAP (хотя, по чесноку, чаще пишу классы  ). А "перепрыгивание" еще много где не работает (или работает не так как хотелось бы). В тех же классах из метода базового класса уже не "перепрыгнуть" в наследника, и все-равно приходится активно работать с репозитарием. Да, и еще, InventMovement и Ко я бы не стал относить к попытке реализации мэппинга, все-таки это InventMovement...   | 
|  | 
|  07.08.2008, 11:28 | #8 | 
| Участник | 
			
			По сути, Map - это тоже класс, реализовывающий экземпляр hash table в АХ. То есть вместо того, чтобы писать свой класс, который будет делать то же самое, что и мап, можно использовать уже написанный. Более того, так как это кернел класс, он будет работать намного быстрее Вашего application level класса. | 
|  | 
|  07.08.2008, 13:58 | #9 | 
| Участник | 
			
			Всем спасибо! В общем понятно. Цитата: Это относится к именно элементу MAP, а не к системному классу Map? | 
|  | 
|  07.08.2008, 14:15 | #10 | 
| Участник | 
			
			http://en.wikipedia.org/wiki/Hash_table Это относится к системному (kernel) классу Map. То, что он системный, значит, что его код написан на C++, а не на Х++. А это существенно ускоряет его работу   | 
|  | 
|  07.08.2008, 14:31 | #11 | 
| Участник | |
|  | 
|  07.08.2008, 14:34 | #12 | 
| Участник | 
			
			Поправочка (спасибо mbelugin) Map реализован как C++ container: http://en.wikipedia.org/wiki/Map_(C%2B%2B_container) | 
|  | 
|  07.08.2008, 14:53 | #13 | 
| MCT | Цитата: 
		
			Сообщение от kashperuk
			   Поправочка (спасибо mbelugin) Map реализован как C++ container: http://en.wikipedia.org/wiki/Map_(C%2B%2B_container) То есть что то типа этого? X++: #include <iostream> #include <map> using namespace std; int main() { typedef map<char, int> mapType; mapType myMap; // insert elements using insert function myMap.insert(pair<char, int>('a', 1)); myMap.insert(pair<char, int>('b', 2)); myMap.insert(pair<char, int>('c', 3)); myMap.insert(pair<char, int>('d', 4)); myMap.insert(pair<char, int>('e', 5)); // erase the first element using the erase function mapType::iterator iter = myMap.begin(); myMap.erase(iter); // output the size of the map cout << "Size of myMap: " << myMap.size() << endl; cout << "Enter a key to search for: "; char c; cin >> c; // find will return an iterator to the matching element if it is found // or to the end of the map if the key is not found iter = myMap.find(c); if( iter != myMap.end() ) cout << "Value is: " << iter->second << endl; else cout << "Key is not in myMap" << endl; // clear the entries in the map myMap.clear(); } | 
|  | 
|  07.08.2008, 14:47 | #14 | 
| Administrator | 
			
			2 Hub: Вы таки спрашиваете про элемент MAP ? Если про элемент - то могу сказать, зачем они нужны. Представьте себе 2 или более таблиц, которые "похожи" по структуре, но в реалии отличаются. К примеру - клиенты, поставщики, сотрудники.... Представьте теперь, что элемент MAP - является своего рода базовым классом над этими таблицами. Т.е. туда можно свалить общий для всех таблиц код. Разница между обычными классами и связкой MAP-Таблица состоит в том, что при разработке - сначала делается базовый класс, а потом его потомки. А тут наоборот. Сначала - таблицы - а потом базовый класс как бы "собирается". При этом, т.к. формально наследования нет - то формально можно создать много MAPов на один и тот же набор таблиц. Только это лишено логического смысла. Вот вкратце описание - для чего нужен элемент MAP 
				__________________ Возможно сделать все. Вопрос времени | 
|  | 
|  07.08.2008, 15:33 | #15 | 
| Участник | Цитата: 
		
			Сообщение от sukhanchik
			   2 Hub: Вы таки спрашиваете про элемент MAP ? Если про элемент - то могу сказать, зачем они нужны. Представьте себе 2 или более таблиц, которые "похожи" по структуре, но в реалии отличаются. К примеру - клиенты, поставщики, сотрудники.... Представьте теперь, что элемент MAP - является своего рода базовым классом над этими таблицами. Т.е. туда можно свалить общий для всех таблиц код. Разница между обычными классами и связкой MAP-Таблица состоит в том, что при разработке - сначала делается базовый класс, а потом его потомки. А тут наоборот. Сначала - таблицы - а потом базовый класс как бы "собирается". При этом, т.к. формально наследования нет - то формально можно создать много MAPов на один и тот же набор таблиц. Только это лишено логического смысла. Вот вкратце описание - для чего нужен элемент MAP | 
|  | 
|  08.08.2008, 11:57 | #16 | 
| Участник | Цитата: 
		
			Сообщение от Inside MS DAX;
			
			 Maps (Data Association Model Elements) provide a useful common interface to data entities and prevent the need to duplicate methods on denormalized tables, but you should use maps only when normalization is not an option. Цитата: 
		
			Сообщение от Raven Melancholic;
			
			 где this это совсем оказывается не this, а ссылка на строку таблицы. Из метода последней вытягивается красивым синтаксисом другой map.... Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы. Последний раз редактировалось avf; 08.08.2008 в 11:59. | 
|  | 
|  11.08.2008, 16:58 | #17 | 
| Участник | 
			
			Я тут ухватился за  Цитата: 
		
			Сообщение от Bishop
			
			 В тех же классах из метода базового класса уже не "перепрыгнуть" в наследника, и все-равно приходится активно работать с репозитарием. Скорость работы обоих специально не сравнивал. Она зависит от результата выборки. На глаз не могу выбрать один либо второй Кому интересно, посмотрите проект, было бы интересно, если бы кто-то замерил время. Первый раз и там и там, ессно, выполняется долго довольно. Через Dictionary X++: public void addIns_OpenOverriddenMethodDef(Editor e) { #AOT #define.AOTDelimiter('\\') // This does not exist in AX versions prior to AX 2009, so I just declare it here TreeNode treeNode = TreeNode::findNode(e.path()); TreeNode treeNodeParent; Dictionary dictionary = new Dictionary(); Counter classCnt = dictionary.classCnt(); Counter iClassCount; ClassId classIdParent; ClassId classIdChild; Counter descendentsCount; SysDictClass dictClassChild; TreeNodeName methodName = treeNode.treeNodeName(); Map map; MapEnumerator mapEnumerator; ; if (subStr(treeNode.treeNodePath(), 1, strLen(#ClassesPath)) == #ClassesPath) { treeNodeParent = TreeNode::findNode(xUtilElements::getNodePathRough(xUtilElements::parentElement(xUtilElements::findTreeNode(treeNode)))); classIdParent = dictionary.className2Id(treeNodeParent.treeNodeName()); map = new Map(Types::String, Types::String); for (iClassCount = 1; iClassCount <= classCnt; iClassCount++) { classIdChild = dictionary.classCnt2Id(iClassCount); if (SysDictClass::isSuperclass(classIdChild, classIdParent)) { descendentsCount++; treeNode = TreeNode::findNode(#ClassesPath + #AOTDelimiter + classId2Name(classIdChild) + #AOTDelimiter + methodName); if (treeNode) { map.insert(treeNode.treeNodePath(), treeNode.AOTparent().treeNodeName()); } } } switch (map.elements()) { case 0: info(strFmt("The method '%1' is not overridden in any of the %2 descendent classes", methodName, descendentsCount)); break; case 1: mapEnumerator = map.getEnumerator(); if (mapEnumerator.moveNext()) treeNode = TreeNode::findNode(mapEnumerator.currentKey()); else error("Internal error. map.elements() == 1, but mapEnumerator did not find it"); break; default: treeNode = TreeNode::findNode(pickList(map, "Method definition", "Pick required class to go to method definition")); } if (treeNode && SysTreeNode::hasSource(treeNode)) treeNode.AOTedit(); } } X++: public void addIns_OpenOverriddenMethodDefXRef(Editor e) { #define.AOTDelimiter('\\') #AOT TreeNode treeNode = TreeNode::findNode(e.path()); TreeNode treeNodeParent; ClassId classIdParent; TreeNodeName methodName = treeNode.treeNodeName(); Map descendents; MapEnumerator descendentsEnumerator; Counter descendentsCount; void findDescendents(ClassId _parentId) { xRefTypeHierarchy typeHierarchy; TreeNode descendent; ; while select typeHierarchy where typeHierarchy.Parent == _parentId && typeHierarchy.BaseType == Types::Class { descendentsCount++; descendent = TreeNode::findNode(#ClassesPath + #AOTDelimiter + typeHierarchy.Name + #AOTDelimiter + methodName); if (descendent) descendents.insert(descendent.treeNodePath(), descendent.AOTparent().treeNodeName()); if (typeHierarchy.Children && typeHierarchy.Id) findDescendents(typeHierarchy.Id); } } ; if (subStr(treeNode.treeNodePath(), 1, strLen(#ClassesPath)) == #ClassesPath) { treeNodeParent = TreeNode::findNode(xUtilElements::getNodePathRough(xUtilElements::parentElement(xUtilElements::findTreeNode(treeNode)))); classIdParent = className2Id(treeNodeParent.treeNodeName()); descendents = new Map(Types::String, Types::String); if (xRefTypeHierarchy::findOrCreate(Types::Class, classIdParent).Children) findDescendents(classIdParent); switch (descendents.elements()) { case 0: info(strFmt(@"The method '%1' is not overridden in any of the %2 descendent classes", methodName, descendentsCount)); break; case 1: descendentsEnumerator = descendents.getEnumerator(); if (descendentsEnumerator.moveNext()) treeNode = TreeNode::findNode(descendentsEnumerator.currentKey()); break; default: treeNode = TreeNode::findNode(pickList(descendents, "@SYS24724", @"Pick required class to go to method definition")); } if (treeNode && SysTreeNode::hasSource(treeNode)) treeNode.AOTedit(); } }  Спасибо Последний раз редактировалось kashperuk; 12.08.2008 в 10:36. Причина: Немного улучшил производительность xRef версии | 
|  | |
| За это сообщение автора поблагодарили: aidsua (1), alex55 (1). | |
|  | 
| 
 |