.RU

Рис. 16.4 - Лекция: Качество по качество это цель инженерной деятельности; построение качественного по (software)...



Рис. 16.4.  Глобальная структура наследования

^ Нижняя часть иерархии

На рис. 16.4 представлен также класс NONE, антипод класса ANY, потомок всех классов, не имеющих собственных наследников и превращающий глобальную иерархию наследования классов в решетку (математическую структуру). NONE не имеет потомков, его нельзя переопределить - это лишь удобная фикция, однако, теоретическое существование такого класса оправдано и служит двум практическим целям:

Первое свойство объясняет, почему значение Void можно присвоить любому элементу ссылочного типа данных. До сих пор статус Void оставался некой загадкой, теперь, когда Void связано с классом NONE, этот статус становится очевидным, официальным и согласующимся с системой типов: по построению NONE является потомком всех классов, а потому мы можем использовать Void как допустимое значение любой ссылки, не нарушая правил описания типов.

По симметрии ко второму свойству заметим, что объявление, начинающееся с feature и экспортирующее все компоненты во все классы, написанные разработчиком, считается сокращением от feature {ANY}. Для повторного экспорта во все классы компонента родителя, доступ к которому был ограничен, можно использовать предложение export {ANY} или его не столь очевидное сокращение export.

Классы ANY и NONE обеспечивают замкнутость системы типов и полноту структуры наследования: решетка (это строго определенный математический термин) имеет свой верхний и нижний элемент.

^ Универсальные компоненты

Вот лишь некоторые компоненты, содержащиеся в классе GENERAL, а значит, доступные всем другим классам. Часть из них была введена и использована в предшествующих лекциях курса:

^ Замороженные компоненты

При обсуждении идеи наследования неоднократно подчеркивался принцип Открыт-Закрыт - право, взяв компонент класса-родителя, переопределить его, возложив на него иные задачи. Могут ли появиться причины запрета такой возможности?

^ Запрет повторного объявления

Обсуждение утверждений в начале лекции дало нам теоретическое понимание сути переопределений. Часть "Открыт" принципа Открыт-Закрыт дает возможность изменять компоненты потомков, но под контролем утверждений. Разрешены лишь те повторные объявления, для которых реализация согласуется со спецификацией, заданной предусловием и постусловиям оригинала.

В ряде случаев клиентам класса и клиентам классов потомков нужна гарантия, что компонент не только соблюдает спецификацию, но и пользуется в точности исходной реализацией. Достичь этого можно лишь "заморозив" его реализацию - полностью запретив переопределение компонента. Подобную возможность дает простая языковая конструкция:

frozen feature_name ... is... Остальные объявления - как обычно...

При таком описании ни один из потомков класса не может включать данный компонент в предложения redefine и undefine ни под своим, ни под любым другим именем (смена имен, конечно же, по-прежнему разрешена). Отложенный компонент по своей сути должен быть переопределен и, следовательно, не может быть заморожен.

^ Фиксированная семантика компонентов copy, clone и equality

Чаще всего замороженные (frozen) компоненты применяются в операциях общего назначения, подобных тем, что входили в состав класса GENERAL. Так, есть две версии базовой процедуры копирования:

copy, frozen standard_copy (other: ...) is

-- скопировать поля other в поля текущего объекта.

require

other_not_void: other /= Void

do

...

ensure

equal (Current, other)

end

Два компонента (copy и standard_copy) описаны как синонимы. Правила разрешают совместно описывать два компонента класса, если они имеют общее определение. Заметьте, в данном случае только один из компонентов допускает повторное объявление, второй - заморожен. В итоге потомки вправе переопределить copy, что необходимо, например классам ARRAY и STRING, которые сравнивают содержимое, а не значение указателей. Однако параллельно удобно иметь и замороженный вариант компонента для вызова при необходимости исходной операции - standard_copy.

Компонент clone, входящий в состав класса GENERAL, тоже имеет "двойника" standard_clone, однако обе версии заморожены. Зачем понадобилось замораживать clone? Причина кроется не в запрете задания иной семантики операции клонирования, а в необходимости сохранения совместимости семантик copy и clone, что, как побочный эффект, облегчает задачу разработчика. Общий вид объявления clone таков:

frozen clone (other:...): ... is

-- Void если other пуст; иначе вернуть новый объект, содержимое которого скопировано

из other.

do

if other /= Void then

Result := "Новый объект того же типа, что other"

Result.copy (other)

end

ensure

equal (Result, other)

end

Фраза "^ Новый объект того же типа, что other" есть неформальное обозначение вызова функции, которая создает и возвращает объект того же типа, что и other. (Result равен Void, если other - "пустой" указатель.)

Несмотря на замораживание компонента clone, он будет изменяться, соответствуя любому переопределению copy, например в классах ARRAY и STRING. Это удобно (для смены семантики copy-clone достаточно переопределить copy) и безопасно (задать иную семантику clone было бы, скорее всего, ошибкой).

Переопределять clone не нужно (да и нельзя), однако при переопределении copy понадобится переопределить и семантику равенства. Как сказано в постусловиях компонентов copy и clone, результатом копирования должны быть тождественные объекты. Сама функция equal, по сути, зафиксирована, как и clone, но она зависит от компонентов, допускающих переопределение:

frozen equal (some, other: ...): BOOLEAN is

-- Обе сущности some и other пусты или присоединены

-- к объектам, которые можно считать равными?

do

Result := ((some = Void) and (other = Void)) or else some.is_equal (other)

ensure

Result = ((some = Void) and (other = Void)) or else some.is_equal (other)

end

Вызов equal (a, b) не соответствует строгому ОО-варианту a.is_ equal (b), но на практике выгодно отличается от него, будучи применим, даже если a или b пусто. Базовый компонент is_equal не заморожен и требует согласованного переопределения в любом классе, переопределяющем copy. Это делается для того, чтобы семантика равенств оставалась совместимой с семантикой copy-clone, а постусловия copy и clone были по-прежнему верными.

^ Не злоупотребляйте замораживанием

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

Замораживание компонентов не следует делать по соображениям эффективности. (Эту ошибку иногда совершают программисты, работающие на C++ или Smalltalk, которым внушили мысль, будто динамическое связывание накладно и его нужно по возможности избегать.) Хотя вызов замороженных компонентов означает отсутствие динамического связывания, это лишь побочный эффект механизма frozen, а не его конечная цель. Выше мы подробно говорили о том, что безопасное статическое связывание - это проблема оптимизации, и решает ее компилятор, а не программист. В грамотно спроектированном языке компилятор обладает всем необходимым для такой и даже более сильной оптимизации, скажем, для подстановки тела функции в точку вызова (routine inlining). Поиск возможностей оптимизации - задача машин, а не человека. Пользуйтесь frozen в редких, но важных для себя случаях, когда это действительно необходимо (для обеспечения точного соответствия семантике исходной реализации), и пусть ваш язык и ваш компилятор делают свою работу.

^ Ограниченная универсальность

Расширяя базовое понятие класса, мы представляли наследование и универсальность (genericity) как своего рода "партнеров". Объединить их нам позволило знакомство с полиморфными структурами данных: в контейнер - объект, описанный сущностью типа SOME_CONTAINER_TYPE [T] с родовым параметром T - можно помещать объекты не только самого типа T, но и любого потомка T. Однако есть и другая интересная комбинация партнерства, в которой наследование используется для задания ограничения на возможный тип фактического родового параметра класса.

^ Вектора, допускающие сложение

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

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

indexing

description: "Векторы со сложением"

class

^ VECTOR [G]

feature -- Доступ

count: INTEGER

-- Количество элементов

item, infix "@" (i: INTEGER): G is

-- Элемент вектора с индексом i (нумерация с 1)

require ... do

...

end

feature -- Основные операции

infix "+" (other: VECTOR [G]): VECTOR is

-- Поэлементное сложение текущего вектора с other

require ... do

...

end

... Прочие компоненты ...

invariant

non_negative_count: count >= 0

end

Применение инфиксной записи продиктовано соображениями удобства. Для удобства введены и синонимы в обозначении i-го компонента вектора: v.item (i) или просто v @ i.

Обратимся к функции "+". Сначала сложение двух векторов кажется очевидным и состоящим в суммировании элементов на соответствующих местах. Общая его схема такова:

infix "+" (other: VECTOR [G]): VECTOR is

-- Поэлементное сложение текущего вектора с other

require

count = other.count

local

i: INTEGER

do

"Создать Result как массив из count элементов"

from i := 1 until i > count loop

Result.put(item (i) + other.item (i), i)

i := i + 1

end

end

Выражение в прямоугольнике - результат сложения i-го элемента текущего вектора с i-м элементом other. Процедура put сохраняет это значение в i-м элементе Result, и хотя она не показана в классе VECTOR, данная процедура в нем, безусловно, присутствует.




Рис. 16.5.  Поэлементное сложение векторов

Но подобная схема не работает! Операция +, которую мы определили для сложения векторов (VECTOR), здесь применяется к объектам совсем другого типа (G), являющегося родовым параметром. По определению, родовой параметр представлен неизвестным типом - фактическим параметром, появляющимся только тогда, когда нам понадобится для каких либо целей родовой класс. Процесс порождения класса при задании фактического родового параметра называется родовым порождением (generic derivation). Если фактическим параметром служит INTEGER либо иной тип (класс), содержащий функцию infix "+" правильной сигнатуры, корректная работа обеспечена. Но что если параметром станет ELLIPSE, STACK, EMPLOYEE или другой тип без операции сложения?

С прежними родовыми классами: контейнерами STACK, LIST и ARRAY - этой проблемы не возникало, поскольку их действия над элементами (типа G как формального параметра) были универсальны - операции (присваивание, сравнение) могли выполняться над элементами любого класса. Но для абстракций, подобных векторам, допускающих сложение, нужно ограничить круг допустимых фактических родовых параметров, чтобы быть уверенными в допустимости проектируемых операций.

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

^ Не ОО-подход

Переходя к решению этой проблемы, посмотрим, как с такой задачей справлялись другие, не ОО-языки.

В языке Ada нет классов, но зато есть пакеты для группировки взаимосвязанных типов и операций. Пакет может быть родовым, с родовыми параметрами, представляющими типы. При этом возникает та же проблема: пакет VECTOR_PROCESSING может включать объявление типа VECTOR и эквивалент нашей функции infix "+".

Решение в языке Ada рассматривает необходимые операции, например инфиксное сложение, как родовые параметры. Параметрами пакета могут быть не только типы, как при объектном подходе, но и подпрограммы. Например:

generic

type G is private;

with function "+" (a, b: G) return G is ;

with function "*" (a, b: G) return G is ;

zero: G; unity: G;

package VECTOR_HANDLING is

... Интерфейс пакета ...

end VECTOR_HANDLING

Заметим, что наряду с типом G и подпрограммами родовым параметром служит значение zero - нулевой элемент сложения. Типичное использования пакета:

package BOOLEAN_VECTOR_HANDLING is

new VECTOR_HANDLING (BOOLEAN, "or", "and", false, true);

В этом примере логическая операция or используется как сложение, and - умножение, а также задаются соответствующие значения для zero и unity. Подробнее мы обсудим этот пример в одной из следующих лекций курса.

Являясь решением для Ada, данный прием не применим в объектной среде. Основа ОО-подхода - приоритет типов данных над операциями при декомпозиции ПО, чьим следствием является отсутствие независимых операций. Всякая операция принадлежит некоторому типу данных, основанному на классе. Следовательно, возникшая "на пустом месте" функция, скажем, infix "+", не может быть фактическим родовым параметром, стоящим в одном ряду с типами INTEGER и BOOLEAN. То же касается и значений, таких как zero и unity, обязанных знать свое место - быть компонентами класса - вполне респектабельными членами ОО-сообщества.

^ Ограничение родового параметра

Эти наблюдения дают решение. Мы должны оперировать исключительно терминами классов и типов.

Потребуем, чтобы любой фактический параметр, используемый классом VECTOR (в других примерах по аналогии), был типом, поставляемым с множеством операций: infix "+", zero для инициализации суммы и т.д. Владея наследованием, мы знаем, как снабдить тип нужными операциями, - нужно просто сделать его потомком класса, отложенного или эффективного, обладающего этими операциями.

Синтаксически это выглядит так:

class C [G -> CONSTRAINING_TYPE] ... Все остальное как обычно ...

где CONSTRAINING_TYPE - произвольный тип, именуемый родовым ограничением (generic constraint). Символ -> обозначает стрелку на диаграммах наследования. Результат этого объявления в том, что:

Какое родовое ограничение использовать для класса VECTOR? Обсуждая множественное наследование, мы ввели в рассмотрение NUMERIC - класс объектов, допускающих базисные арифметические операции: сложение и умножение с нулем и единицей (лежащая в его основе математическая структура называется кольцом). Эта модель кажется вполне уместной, хотя нам необходимо пока только сложение. Соответственно, класс будет описан так:

indexing

description: "Векторы, допускающие сложение"

class

^ VECTOR [G -> NUMERIC]

... Остальное - как и раньше (но теперь правильно!) ...

После чего ранее некорректная конструкция в теле цикла

Result.put(item (i) + other.item (i), i)

становится допустимой, поскольку item (i) и other.item (i) имеют тип G, а значит, к ним применимы все операции NUMERIC, включая, инфиксный "+".

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

^ VECTOR [NUMERIC]

VECTOR [REAL]

VECTOR [COMPLEX]

Класс EMPLOYEE не порожден от NUMERIC, так что попытка использовать VECTOR [EMPLOYEE] приведет к ошибке времени компиляции.

Абстрактный характер NUMERIC не вызывает никаких проблем. Фактический параметр при порождении может быть как эффективным (примеры выше), так и отложенным (VECTOR [NUMERIC_COMPARABLE]), если он порожден от NUMERIC.

Аналогично описываются класс словаря и класс, поддерживающий сортировку:

class DICTIONARY [G, H -> HASHABLE] ...

class SORTABLE [G -> COMPARABLE] ...

^ Игра в рекурсию

Вот некий трюк с нашим примером: спросим себя, возможен ли вектор векторов? Допустим ли тип VECTOR [VECTOR [INTEGER]]?

Ответ следует из предыдущих правил: только если фактический родовой параметр совместим с NUMERIC. Сделать это просто - породить класс VECTOR от класса NUMERIC (см. упражнение 16.2):

indexing

description: "Векторы, допускающие сложение"

class

^ VECTOR [G -> NUMERIC]

inherit

NUMERIC

... Остальное - как и раньше...

Векторы, подобные этому, можно и впрямь считать "числовыми". Операции сложение и умножение дают структуру кольца, в котором роль нуля (zero) играет вектор из G-нулей, и роль единицы (unity) - вектор из G-единиц. Операция сложения в этом кольце - это, строго говоря, векторный вариант infix "+", речь о котором шла выше.

Можно пойти дальше и использовать VECTOR [VECTOR [VECTOR [INTEGER]]] и так далее - приятное рекурсивное приложение ограниченной универсальности.

^ И снова неограниченная универсальность

Конечно же, не все случаи универсальности ограничены. Форма - STACK [G] или ARRAY [G] - по-прежнему существует и называется неограниченной универсальностью. Пример DICTIONARY [G, H -> HASHABLE] показывает, что класс одновременно может иметь как ограниченные, так и неограниченные родовые параметры.

Изучение ограниченной универсальности дает шанс лучше понять неограниченный случай. Вы, конечно же, вывели правило, по которому class C [G] следует понимать как class C [G -> ANY]. Поэтому если G - неограниченный типовой параметр (например, класса STACK), а x - сущность, имеющая тип G, то мы точно знаем, что можем делать с сущностью x: читать и присваивать значения, сравнивать (=, /=), передавать как параметр и применять в универсальных операциях clone, equal и прочее.

^ Попытка присваивания

Наша следующая техника адресуется к тем областям Объектной страны, в которых из страха тиранического поведения мы не можем позволить править простым правилам типизации, не встречая никакого сопротивления.

^ Когда правила типов становятся несносными

Цель правил типов, введенных вместе с наследованием, в достижении статически проверяемого динамического поведения, так чтобы система, прошедшая проверку при компиляции, не выполняла неадекватных операций над объектами во время выполнения.

Вот два основных правила, представленных в первой лекции о наследовании (лекция 14).

Правило Вызова Компонентов не является причиной каких-либо проблем - это фундаментальное условие всякой работы с объектами. Естественно, что обращаясь к компоненту объекта, нужно проверить, действительно ли данный класс предлагает и экспортирует данный компонент.

Правило Совместимости Типов требует больше внимания. Оно предполагает наличие у нас всей информации о типах объектов, с которыми мы работаем. Как правило, это так, - создав объекты, мы знаем, чем они являются, но иногда информация может частично отсутствовать. Вот два таких случая.

Давайте займемся исследованием примеров этих двух случаев. Рассмотрим для начала полиморфную структуру данных, такую как список геометрических фигур:

figlist: LIST [FIGURE]

В предыдущих лекциях рассматривалась иерархия наследования фигур. Пусть нам необходимо найти самую длинную диагональ среди всех прямоугольников списка (и вернуть -1, если прямоугольников нет). Сделать это непросто. Выражение item (i).diagonal, где item (i) - i-й элемент списка, идет вразрез с правилом вызова компонентов: item (i) имеет тип FIGURE, а этот класс, в отличие от его потомка RECTANGLE, не содержит в своем составе компонента diagonal. Решение, используемое до сих пор, изменяло определение класса, - в нем появлялся атрибут, задающий тип фигуры. Однако это решение не столь элегантно, как нам хотелось бы.

Теперь пример второго рассматриваемого случая. Пусть имеется механизм хранения объектов в файле или передачи их по сети, аналогичный универсальному классу STORABLE, описанному нами ранее. Для получения объекта используем:

my_last_book: BOOK

...

my_last_book := retrieved (my_book_file)

Значение, возвращаемое retrieved, имеет тип STORABLE библиотеки Kernel, хотя с тем же успехом оно может иметь тип ANY. Но мы не ожидали STORABLE или ANY, - мы надеялись получить именно BOOK. Присваивание my_last_book нарушает правило Совместимости Типов.

Даже если написать собственную функцию retrieved, учитывающую специфику приложения и объявленную с подходящим типом, вам не удастся полностью на нее положиться. В отличие от объектов вашего ПО, в котором согласованность типов гарантируется действующими правилами, данный объект к вам поступает со стороны. При его получении вы могли ошибиться в выборе имени файла и прочитать объект EMPLOYEE вместо объекта BOOK, файл мог быть подделан, а при сетевом доступе данные могли быть искажены при передаче.

Проблема

Из этих примеров ясно: нам может понадобиться механизм удостоверения типа объекта.

Решение этой проблемы, возникающей в специфических, но критически важных случаях, должно быть найдено без потери преимуществ ОО-стиля разработки. В частности, мы не хотим возвращаться к той схеме, которую сами и осудили:

if "f типа RECTANGLE" then

...

elseif "f типа CIRCLE" then

...

и т.д.

Это решение идет вразрез с принципами Единственного Выбора и Открыт-Закрыт. Избежать риска потерь нам помогут два обстоятельства.

^ Механизм решения

И снова запись механизма решения напрямую вытекает из анализа поставленной проблемы. Введем новую форму присваивания, назвав ее попыткой присваивания (assignment attempt):

target ?= source

Знак вопроса указывает на предварительный характер операции. Пусть сущность target имеет тип T, тогда попытка присваивания дает следующий результат:

На эту инструкцию не действуют никакие ограничения типов, кроме одного: тип target (T) должен быть ссылочным.

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

maxdiag (figlist: LIST [FIGURE]): REAL is

-- Максимальная длина диагонали прямоугольника в списке;

-- если прямоугольников нет, то -1.

require

list_exists: figlist /= Void

local

r: RECTANGLE

do

from

figlist.start; Result := -1.0

until

figlist.after

loop

r ?= figlist.item

if r /= Void then

Result := Result.max (r.diagonal)

end

figlist.forth

end

end

Здесь применяются обычные итерационные механизмы работы с последовательными структурами данных (лекция 5 курса "Основы объектно-ориентированного проектирования"). Компонент start служит для перехода к первому элементу (если он есть), after - для выяснения того, имеются ли еще не пройденные элементы, forth - для перехода на одну позицию, item (определенный, если not after) - для выборки текущего элемента.

В попытке присваивания используется локальная сущность r типа RECTANGLE. Успех присваивания проверяется сравнением значения r с Void. Если r не Void, то r прямоугольник и можно обратиться к r.diagonal. Эта схема проверки вполне типична.

Заметим, что мы никогда не нарушаем правило Вызова Компонентов: обращения к r.diagonal защищены дважды: статически - компилятором, проверяющим, является ли diagonal компонентом класса RECTANGLE, и динамически - нашей гарантией того, что r не Void, а имеет присоединенный объект.

Обращение к элементу списка - потомку класса RECTANGLE, например SQUARE (квадрат), связывает r с объектом, и его диагональ будет участвовать в вычислениях.

Пример с универсальной функцией чтения объектов retrieval выглядит так:

my_last_book: BOOK

... Сравните с := в первой попытке

my_last_book ?= retrieved (my_book_file)

if my_last_book /= Void then

... "Обычные операции над my_last_book" ...

else

... "Полученное не соответствует ожиданию" ...

end

rolevaya-igra-innovacionnie-formi-obucheniya-profsoyuznogo-aktiva.html
rolevaya-strategiya-yamalo-neneckij-avtonomnij-okrug.html
rolevie-igri-na-urokah-inostrannogo-yazika-v-nachalnoj-shkole.html
rolevie-teorii-fenomenologiya-soc-podhodi-k-opredeleniyu-eyo-predmeta-specifika-soc-mesto-soc-psihologii-sredi-dr-nauk.html
rolf-kniper-kniga-izdana.html
roliki-streli-i-komplektuyushie-prajs-list-na-zapasnie-chasti.html
  • occupation.bystrickaya.ru/metodologiya-protivodejstviya-sbornik-materialov-moskva-2007-bbk-71-01-74-200-53-87-7-stranica-17.html
  • essay.bystrickaya.ru/diagnostika-i-formirovanie-korporativnoj-kulturi-organizacii.html
  • school.bystrickaya.ru/113-opisanie-polnogo-cikla-rabot-po-perehodu-federalnogo-obrazovatelnogo-uchrezhdeniya-v-au.html
  • laboratory.bystrickaya.ru/vibor-i-obosnovanie-sredi-peredachi-dannih.html
  • pisat.bystrickaya.ru/torgovogo-doma-biblio-globus-stranica-13.html
  • institute.bystrickaya.ru/glava-poslednij-boevoj-polet-iz-knigi-pod-nami-zemlya-i-more-bd-statya-ekipazh-otvazhnih-pech-virezka-1961.html
  • doklad.bystrickaya.ru/variativnaya-chast-uchebnogo-plana-municipalnogo-obrazovatelnogo-uchrezhdeniya-srednej-obsheobrazovatelnoj-shkoli.html
  • letter.bystrickaya.ru/mgu-prinimaet-uotsona-18-iyunya-v-stenah-loft-proekta-etazhi-startuet-festival-artes-liberales-fakulteta-iskusstv.html
  • student.bystrickaya.ru/-59-operator-cehov-po-prigotovleniyu-kormov-postanovlenie-goskomtruda-sssr-i-sekretariata-vcsps.html
  • literatura.bystrickaya.ru/solomon-shulman-stranica-5.html
  • uchit.bystrickaya.ru/tema-11-osnovi-bezopasnosti-zhiznedeyatelnosti-anatomno-fiziologicheskie-mehanizmi-bezopasnosti-i-fiziologiya-truda.html
  • teacher.bystrickaya.ru/filosofskie-osnovi-mirovozzreniya-stranica-5.html
  • exchangerate.bystrickaya.ru/610-kalendarnij-grafik-rabot-vipolnyaemih-v-podgotovitelnij-period-stroitelstva.html
  • university.bystrickaya.ru/glava-29-voznoshenie-molitvi-vo-vsyakoe-vremya-dzhon-f-makartur.html
  • literature.bystrickaya.ru/delat-reklamu-i-sozdavat-reklamu-dva-raznih-ponyatiya-reklamnoe-iskusstvo.html
  • control.bystrickaya.ru/ekonomicheskie-metodi-upravleniya-zapasami-produkcii-materialno-tehnicheskogo-naznacheniya-na-primere-oao-uralkalij.html
  • lektsiya.bystrickaya.ru/pravila-akkreditacii-subektov-nauchnoj-i-ili-nauchno-tehnicheskoj-deyatelnosti.html
  • kanikulyi.bystrickaya.ru/zanyatie-lekciya-chto-takoe-muzej-muzeevedenie-kak-nauchnaya-disciplina-ponyatie-muzej.html
  • thesis.bystrickaya.ru/primernaya-programma-professionalnogo-modulya-vipolnenie-mehanizirovannih-rabot-na-zhivotnovodcheskih-kompleksah-i-mehanizirovannih-fermah-2010-g.html
  • znanie.bystrickaya.ru/7-sistema-vospitatelnoj-raboti-uchashihsya-publichnij-otchet-mou-srednyaya-obsheobrazovatelnaya-shkola-2-kachkanarskogo.html
  • occupation.bystrickaya.ru/metodicheskie-ukazaniya-po-kursu-issledovanie-sistem-upravleniya-dlya-studentov-zaochnogo-otdeleniya-novosibirsk-2004-g-stranica-2.html
  • nauka.bystrickaya.ru/variant-6-3-literatura.html
  • learn.bystrickaya.ru/glava-5-v-napisanii-etoj-knigi-mne-pomogali-mnogie-lyudi-dalekie-i-blizkie-horoshie-znakomie-i-te-s-kotorimi.html
  • institut.bystrickaya.ru/stacionarnij-zakritoe-akcionernoe-obshestvo.html
  • control.bystrickaya.ru/ekologicheskij-monitorin-g-uchebno-metodicheskij-kompleks-stranica-3.html
  • school.bystrickaya.ru/80386-processor-chast-3.html
  • uchenik.bystrickaya.ru/costyazaniya-po-informatike-olimpiadi.html
  • letter.bystrickaya.ru/ob-obshestvennoj-palate-kaluzhskoj-oblasti.html
  • knowledge.bystrickaya.ru/mitinga-obshestvennih-organizacij-primorskogo-kraya-pod-devizom-primore-za-stabilnost.html
  • znanie.bystrickaya.ru/analiz-fotograficheskih-svojstv-fotoplenok-chast-8.html
  • knowledge.bystrickaya.ru/nashego-uroka-el-tok-v-zhidkostyah-elektroliz.html
  • uchitel.bystrickaya.ru/programma-povisheniya-kvalifikacii-pedagogicheskih-rabotnikov-po-prioritetnomu-napravleniyu-pedagogika-i-psihologiya-po-programme.html
  • knowledge.bystrickaya.ru/neobuzdannij-po-obrazu-kotorogo-mi-sozdani.html
  • zanyatie.bystrickaya.ru/tehnicheskie-resheniya-postroeniya-gorodskoj-operatorskoj-seti-na-baze-tehnologii-optical-ethernet.html
  • vospitanie.bystrickaya.ru/yazicheskie-runi-i-monoteizm-skazka-dom-s-krasnim-cvetkom.html
  • © bystrickaya.ru
    Мобильный рефератник - для мобильных людей.