Пост

Хочу универсально! Часть 2

Продолжение истории про то, как начинающий разработчик Вася проходит путь от простой задачки к созданию своего механизма.


Здесь можно прочитать первую часть статьи

Нужно больше универсальности!

Начинающий разработчик Василий не так давно начал свой путь универсализации всего и вся

И теперь не собирается останавливаться.

На данный момент Вася имеет метод, который открывает значение текущей ячейки. Но что, если расширить функционал? Методы, которые позволят не только открывать текущее значение, но и присваивать его… И независимо от того, находимся ли мы на клиенте или сервере…

Введение

Василий берёт блокнот и записывает:

  • программно получить значение текущей ячейки (на клиенте и на сервере)
  • программно установить значение текущей ячейки (на клиенте и на сервере)
  • интерактивно показать значение текущей ячейки (на клиенте)
  • чистить кэш
  • сохранять сессию открытых окон…

Почесав затылок, наш начинающий универсальщик скрепя когтями решает отложить часть пунктов «на потом» и сократить список:

  • программно получить значение текущей ячейки (на клиенте и на сервере)
  • программно установить значение текущей ячейки (на клиенте и на сервере)
  • интерактивно показать значение текущей ячейки (на клиенте)

Для всего этого нужна хорошая обёртка. Василий переворачивает страницу блокнота и пишет:

  • Возможность передать в метод любую таблицу. Ведь, если на текущем инструменте несколько таблиц, то нужно обеспечить возможность работы со всеми.
  • Работать как «&НаСервере», так и «&НаКлиенте». Естественно, где это возможно.
  • Изолированность — методы должны быть вынесены так, чтобы их было несложно перенести в другой инструмент.

Разработчик окидывает взглядом текущий функционал, который он написал в первой статье

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	ПутиКДаннымЭлементовФормы = Новый Структура;

	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры


&НаКлиенте
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции


&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеЯчейки);
	
КонецПроцедуры

Первое, что попадается на глаза разработчику Васе — метод «ПриСозданииНаСервере». Его используют очень часто для разного рода действий и загромождать своим кодом будет не очень удобно.

- Нужно вынести в новый метод!

И Василий решает содержимое события «ПриСозданииНаСервере» вынести в отдельный метод. А заодно и протестировать возможность конфигуратора, о которой он вроде бы слышал, но никогда не пробовал — рефакторинг кода.

Начинающий разработчик выделяет нужный код, нажимает правую кнопку мыши и выбирает «Рефакторинг» → «Выделить фрагмент»

Выделение фрагмента

В появившемся окошке он вводит название своего нового метода: ОбновитьПутиКДаннымЭлементовФормы

Имя нового метода

И в результате получает то, что хотел. Конфигуратор сам создал новую процедуру и сделал вызов на неё

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ОбновитьПутиКДаннымЭлементовФормы();
	
КонецПроцедуры

&НаСервере
Процедура ОбновитьПутиКДаннымЭлементовФормы()
	
	ПутиКДаннымЭлементовФормы = Новый Структура;
	
	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

- Не зря я учился в Великой Школе Одинэсников Имени Желтого Чайника!

В результате, если Вася захочет поделиться наработками, то применить их в другом инструменте будет теперь чуточку проще. Есть ещё один приятный бонус — возможность дополнительно вызывать этот метод по мере необходимости (Василий пока ещё не понял зачем, но об этом позднее…).

Для этого сразу же ранее написанный метод «ПутьКДаннымЭлементаФормы» делаем &НаКлиентеНаСервереБезКонтекста. Таким образом один и тот же метод будет доступен и на сервере и на клиенте.

1
2
3
4
5
6
7
8
&НаКлиентеНаСервереБезКонтекста
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции

Василий знает, что при такой директиве метод «теряет» контекст формы, а значит больше не видит её свойств, элементов, реквизитов и так далее. Но как же теперь с этим работать?

Наш разработчик будет просто передавать форму напрямую.

1
2
3
4
5
6
7
8
&НаКлиентеНаСервереБезКонтекста
Функция ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ЭтаФорма.ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции

Получается, что, независимо от того, находимся ли мы сейчас на клиенте или же сервере, можно вызвать один и тот же метод и просто передать в него текущую форму:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеЯчейки);
	
КонецПроцедуры

Почва подготовлена. Теперь Василий может использовать этот код для реализации наших новых методов.

- Ну-с, приступим!

1
2
3
4
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)

КонецФункции

Этот метод вернёт значение текущей ячейки. На клиент, на сервер — не важно. А дальше уже мы сможем использовать это по своему усмотрению.

Начинаем с классической проверки:

1
2
3
4
5
6
7
8
9
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	
КонецФункции

И сразу же при помощи волшебного копипаста переносим написанный в прошлой статье код, в наш новый метод:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	Возврат ЗначениеЯчейки;
	
КонецФункции

Написанная функция вернёт нам значение текущей ячейки. Что с ним делать? Именно. Открывать.

1
2
3
4
5
6
7
8
9
&НаКлиенте
Процедура ОткрытьЗначениеТекущейЯчейки(ТаблицаФормы)
	
	ЗначениеТекущейЯчейки = ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы);
	Если НЕ ЗначениеТекущейЯчейки = Неопределено Тогда
		ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеТекущейЯчейки);
	КонецЕсли;
	
КонецПроцедуры

А в нашей команде просто вызываем этот метод:

1
2
3
4
5
6
&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ОткрытьЗначениеТекущейЯчейки(Элементы.Валюты);
	
КонецПроцедуры

Замечательно, теперь наш код стал значительно красивее.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Обработчик команды формы
&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ОткрытьЗначениеТекущейЯчейки(Элементы.Валюты);
	
КонецПроцедуры


//Процедура открывает значение текущей ячейки
&НаКлиенте
Процедура ОткрытьЗначениеТекущейЯчейки(ТаблицаФормы)
	
	ЗначениеТекущейЯчейки = ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы);
	Если НЕ ЗначениеТекущейЯчейки = Неопределено Тогда
		ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеТекущейЯчейки);
	КонецЕсли;
	
КонецПроцедуры

//Функция возвращает значение текущей ячейки
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	Возврат ЗначениеЯчейки;
	
КонецФункции

- Рано ликовать!

У Васи готовы методы

  • программно получить значение текущей ячейки (на клиенте и на сервере)
  • интерактивно показать значение текущей ячейки (на клиенте)

Осталось сделать ещё один

  • программно установить значение текущей ячейки (на клиенте и на сервере)

И снова мы начинаем с проверки. Метод, естественно, будет &НаКлиентеНаСервереБезКонтекста

1
2
3
4
5
6
7
8
9
10
&НаКлиентеНаСервереБезКонтекста
Процедура УстановитьЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы, Значение)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	
	
КонецПроцедуры

Теперь Василию нужно как-то получить не значение в текущей ячейке, а именно саму эту «ячейку», чтобы установить значение.

Но на самом деле , ранее это уже было сделано. В методе ЗначениеТекущейЯчейки():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Функция возвращает значение текущей ячейки
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	Возврат ЗначениеЯчейки;
	
КонецФункции

Да, именно этот кусочек кода нужно выполнить в нашем новом методе. Можно было, конечно, скопировать его и вставить в наш новый метод, но…

Не этому меня учили в Великой Школе Одинэсников Имени Желтого Чайника!

И Василий снова берётся за «рефакторинг». Выделяет наш кусочек кода и выносит в специальный новый метод «ИмяКолонкиТекущейЯчейки»:

1
2
3
4
5
6
7
8
9
10
11
12
&НаКлиентеНаСервереБезКонтекста
Функция ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	Возврат ИмяКолонкиТаблицы;
	
КонецФункции

А в ранее написанной функции теперь просто вызов этого нового метода. Красота. В результате функция стала ещё нагляднее:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИмяКолонкиТекущейЯчейки = ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы);
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТекущейЯчейки, ЗначениеЯчейки);
	
	Возврат ЗначениеЯчейки;
	
КонецФункции

Прекрасно. Теперь у Васи есть метод, который возвращает имя нужно колонки. Осталось только присвоить значение:

1
2
3
4
5
6
7
8
9
10
11
12
13
&НаКлиентеНаСервереБезКонтекста
Процедура УстановитьЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы, Значение)
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяКолонкиТекущейЯчейки = ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы);
	Если ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТекущейЯчейки) Тогда
		ТаблицаФормы.ТекущиеДанные[ИмяКолонкиТекущейЯчейки] = Значение;
	КонецЕсли;
	
КонецПроцедуры

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

Окончательная Васина процедура ```bsl &НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ОбновитьПутиКДаннымЭлементовФормы(); КонецПроцедуры //Процедура обновляет пути для определения реквизита текущей ячейки &НаСервере Процедура ОбновитьПутиКДаннымЭлементовФормы() ПутиКДаннымЭлементовФормы = Новый Структура; Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным); КонецЕсли; КонецЦикла; КонецПроцедуры //Обработчик команды формы &НаКлиенте Процедура ОткрытьЗначениеЯчейки(Команда) ОткрытьЗначениеТекущейЯчейки(Элементы.Валюты); КонецПроцедуры //Процедура открывает значение текущей ячейки &НаКлиенте Процедура ОткрытьЗначениеТекущейЯчейки(ТаблицаФормы) ЗначениеТекущейЯчейки = ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы); Если НЕ ЗначениеТекущейЯчейки = Неопределено Тогда ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеТекущейЯчейки); КонецЕсли; КонецПроцедуры //Процедура устанавливает значение текущей ячейки &НаКлиентеНаСервереБезКонтекста Процедура УстановитьЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы, Значение) Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли; ИмяКолонкиТекущейЯчейки = ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы); Если ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТекущейЯчейки) Тогда ТаблицаФормы.ТекущиеДанные[ИмяКолонкиТекущейЯчейки] = Значение; КонецЕсли; КонецПроцедуры //Функция возвращает значение текущей ячейки &НаКлиентеНаСервереБезКонтекста Функция ЗначениеТекущейЯчейки(ЭтаФорма, ТаблицаФормы) Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат Неопределено; КонецЕсли; ИмяКолонкиТекущейЯчейки = ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы); ЗначениеЯчейки = Неопределено; ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТекущейЯчейки, ЗначениеЯчейки); Возврат ЗначениеЯчейки; КонецФункции //Функция возвращает имя колонки текущей ячейки &НаКлиентеНаСервереБезКонтекста Функция ИмяКолонкиТекущейЯчейки(ЭтаФорма, ТаблицаФормы) ИмяПоляКолонки = ТаблицаФормы.ТекущийЭлемент.Имя; ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ЭтаФорма, ИмяПоляКолонки); СоставПутиКДанным = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь); ИмяКолонкиТаблицы = СоставПутиКДанным[СоставПутиКДанным.ВГраница()]; Возврат ИмяКолонкиТаблицы; КонецФункции ```

Замечтательно! Довольный программист потирает лапки и идёт наслаждаться победой. Но не полной. Осталось придумать, как теперь завернуть это в удобный механизм. Но об этом он подумает завтра.

Кстати. Забыл сказать, что Василий - кот.

Авторский пост защищен лицензией CC BY 4.0 .