Принципы GRASP. Шаблоны проектирования GRASP

Принципы GRASP. Шаблоны проектирования GRASP

2 мая 2010 в 16:34

GRASP паттерны проектирования

  • Совершенный код

Известно понятие внешнего контроллера (Front Controller), который представляет всю систему в целом (агрегирует весь функционал системы в одном классе).

Примером контроллера является класс Administrator, реализующий вариант использования системы администратором из отдела комплектации рейсов.

Использование контроллеров позволяет отделить логику от представления, тем самым повышая возможность повторного использования кода.

Полиморфизм (Polymorphism)

Шаблон полиморфизм позволяет обрабатывать альтернативные варианты поведения на основе типа. При этом, альтернативные реализации приводятся к обобщенному интерфейсу.

Рассмотрим интеграцию системы с внешними компонентами расчета тарифов на перевозку груза. Классы LocalTarificator и WorldWideTarificator являются адаптерами к соответствующим внешним компонентам.

Применение шаблона полиморфизм позволяет в будущем легко модифицировать систему.

Чистая выдумка (Pure Fabrication)

Существует понятие модели программирования по предметной области, согласно которой, каждой сущности из предметной области соответствует один или более классов программной среды. При этом, обязанности взаимодействия сущностей, как правило накладываются на них самих. Такой подход имеет очевидный недостаток - высокая связность модулей системы. Шаблон чистая выдумка позволяет решить данную проблему, путем введения в программную среду дополнительного класса (не отражающего реальной сущности из предметной области) и наделение его требуемыми обязанностями.

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

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

Перенаправление (Indirection)

Шаблон перенаправление реализует низкую связность между классами, путем назначения обязанностей по их взаимодействию дополнительному объекту - посреднику.

Примером данного шаблона может служить класс ClientsSaver (см. Чистая выдумка), который является промежуточным слоем между сущностями клиентов и хранилищем, в котором они будут сохранены. Кроме того, контроллер из триады MVC является посредником между данными их их представлением.

GRASP (General Responsibility Assignment Software Patterns - общие образцы распределения обязанностей) - паттерны, используемые в объектно-ориентированном проектировании для решения общих задач по назначению обязанностей классам и объектам.

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

Information Expert (Информационный эксперт)

Шаблон Information Expert определяет базовый принцип назначения обязанностей. Он утверждает, что обязанности должны быть назначены объекту, который владеет максимумом необходимой информации для выполнения обязанности. Такой объект называется информационным экспертом . Возможно, этот шаблон является самым очевидным из девяти, но вместе с тем и самым важным.

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

Creator (Создатель)

Шаблон Creator решает, кто должен создавать объект. Фактически, это применение шаблона Information Expert к проблеме создания объектов. Более конкретно, нужно назначить классу B обязанность создавать экземпляры класса A, если выполняется как можно больше из следующих условий:

  • Класс B содержит или агрегирует объекты A.
  • Класс B записывает экземпляры объектов A.
  • Класс B активно использует объекты A
  • Класс B обладает данными инициализации для объектов A.

Альтернативой создателю является шаблон проектирования Фабрика . В этом случае создание объектов концентрируется в отдельном классе.

Controller (Контроллер)

Контроллер берёт на себя ответственность за выполнение операций, приходящих от пользователя и часто выполняет сценарий одного или нескольких вариантов использования (например, один контроллер может обрабатывать сценарии создания и удаления пользователя). Как правило, контроллер не выполняет работу самостоятельно, а делегирует обязанности компетентным объектам.

Иногда класс-контроллер представляет всю систему в целом, корневой объект, устройство или важную подсистему (внешний контроллер ).

Использование контроллеров позволяет отделить логику от представления, тем самым повышая возможность повторного использования кода.

Low Coupling (Слабая связанность)

Low Coupling - это принцип, который позволяет распределить обязанности между объектами таким образом, чтобы степень связанности между системами оставалась низкой. Степень связанности (coupling) - это мера, определяющая, насколько жестко один элемент связан с другими элементами, либо каким количеством данных о других элементах он обладает. Элемент с низкой степенью связанности (или слабым связыванием) зависит от не очень большого числа других элементов и имеет следующие свойства:

  • Малое число зависимостей между классами (подсистемами).
  • Слабая зависимость одного класса (подсистемы) от изменений в другом классе (подсистеме).
  • Высокая степень повторного использования подсистем.

Low Coupling позволяет избежать следующих проблем:

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

High Cohesion (Сильное зацепление)

High Cohesion - это принцип, который задаёт свойство сильного зацепления внутри подсистемы. Классы (подсистемы) таким образом получаются сфокусированными, управляемыми и понятными. Зацепление (cohesion) (или более точно, функциональное зацепление) - это мера связанности и сфокусированности обязанностей класса. Считается что объект (подсистема) обладает высокой степенью зацепления, если его обязанности тесно связаны между собой и он не выполняет огромных объемов работы.

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

  • Трудность понимания.
  • Сложность при повторном использовании.
  • Сложность поддержки.
  • Ненадежность, постоянная подверженность изменениям.

Классы с низкой степенью зацепления, как правило, являются слишком «абстрактными» или выполняют обязанности, которые можно легко распределить между другими объектами.

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

Polymorphism (Полиморфизм)

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

Пример: Интеграция разрабатываемой системы с различными внешними системами учета налогов. Используются локальные программные объекты, обеспечивающие адаптацию (Адаптеры). При отправке сообщения к такому объекту выполняется обращение к внешней системе с использованием ее собственного программного интерфейса. Использование полиморфизма здесь оправдано для возможной адаптации к различным внешним системам.

Pure Fabrication (Чистая выдумка)

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

Существует понятие модели программирования по предметной области, согласно которой, каждой сущности из предметной области соответствует один или более классов программной среды. При этом, обязанности взаимодействия сущностей, как правило накладываются на них самих. Такой подход имеет очевидный недостаток - высокая связность модулей системы. Шаблон чистая выдумка позволяет решить данную проблему, путем введения в программную среду дополнительного класса (не отражающего реальной сущности из предметной области) и наделение его требуемыми обязанностями.

Indirection (Посредник)

Indirection поддерживает слабую связанность (и возможность повторного использования) путём назначения обязанностей посредника между ними промежуточному объекту. Пример: Model-View-Controller , который позволяет ослабить связь между данными и их представлением с помощью введения класса-посредника (контроллер), отвечающего за поведение.

Protected Variations (Сокрытие реализации)

Шаблон Protected Variations защищает элементы от изменения других элементов (объектов или подсистем) с помощью вынесения взаимодействия в фиксированный интерфейс . Всё взаимодействие между элементами должно происходить через него. Поведение может варьироваться лишь с помощью создания другой реализации интерфейса.

Advertisements

Опытные разработчики объектно-ориентированных систем сформулировали об­щие принципы истандартные решения , помогающие в разработке программного обеспечения. Если эти принципы и идиомы систематизировать и структуриро­вать, а также присвоить им имена, то их можно применять в качествешаблонов (patterns).

Приведем пример одного из таких шаблонов:

В объектно-ориентированной технологии проектирования шаблоном назы­вают именованное описание проблемы и ее решения, которые можно применить при разработке других систем. (Другими словами, шаблон – это именованная пара "проблема/решение ", содер­жащая рекомендации для применения в различных конкретных ситуациях, которую можно использовать в различных контекстах.)

Имена шаблонов

Именование шаблонов, методов и принципов имеет следующие преимущества:

    Позволяет зафиксировать понятие в памяти;

    Облегчает общение.

В частности, шаблоны GRASPимеют осмыс­ленные имена, например,Information Expert (Эксперт),Creator (Создатель),Pro ­ tected Variations (Защищенные вариации).

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

Применение шаблонов GRASP

Ниже приводится описание основных пяти шаблонов GRASP:

  • Information Expert

  • High Cohesion

    Low Coupling

    Controller

Применение этих шаблонов касается основных и фундаментальных вопросов проектирования.

Система обозначений диаграммы классов в языке UML

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

Рисунок 2.1 – Имена методов программных классов

Система обозначений диаграммы классов будет использоваться при описа­нии шаблонов.

Шаблон Information Expert

Решение. Назначить обязанность информационному эксперту – классу, у ко­торого имеется информация, требуемая для выполнения обязанности.

Проблема. Каков наиболее общий принцип распределения обязанностей меж­ду объектами при объектно-ориентированном проектировании?

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

Пример . В приложении POS-системы ТТ некоторому классу необходимо знать общую сумму продажи.

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

С этой точки зрения можно сформулировать следующее утверждение: Какой класс должен отвечать за знание общей суммы продажи?

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

Теперь возникает ключевой вопрос: на основе какой модели нужно анали­зировать информацию – модели предметной области или проектирования? Мо­дель предметной области иллюстрирует концептуальные классы из предметной области системы, а в модели проектирования показаны программные классы.

Ответ на этот вопрос сводится к следующему:

    если в модели проектирования имеются соответствующие классы, в пер­вую очередь, следует использовать ее;

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

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

Чтобы рассмотреть этот пример подробнее, обратимся к фрагменту модели предметной области, представленному на рис. 2.2:

Рисунок 2.2 – Ассоциации объекта Sale

Какая информация требуется для вычисления общей суммы? Необходимо узнать стоимость всех проданных товаровSalesLineItemи просуммировать эти промежуточные суммы. Такой информацией обладает лишь экземпляр объект,Sale. Следовательно, с точки зрения шаблонаInformationExpertобъектSaleподходит для выполнения этой обязанности, т.е. являетсяинформационным экспертом (informationexpert).

Как уже упоминалось, подобные вопросы распределения обязанностей зачастую возникают при создании диаграмм взаимодействий. Представьте, что вы приступили к работе, начав создание диаграмм для распределения обязанностей между объектами. Принятые решения иллюстрируются на фрагменте диаграммы взаимодействий, представленном на рис. 2.3.

Рисунок 2.3 – Фрагмент диаграммы взаимодействий

Однако на данном этапе выполнена не вся работа. Какая информация тре­буется для вычисления промежуточной суммы элементов продажи? Необходимы значения атрибутов SalesLineItem.quantityиSalesLineItem.price. Объек­туSalesLineItemизвестно количество товара и известен связанный с ним объ­ектProductSpecification. Следовательно, в соответствии с шаблономExpert, промежуточную сумму должен вычислять объект SalesLineItem. Другими сло­вами, этот объект являетсяинформационным экспертом.

В терминах диаграмм взаимодействий это означает, что объект Saleдолжен передать сообщенияgetSubtotalкаждому объекту SalesLineItem, а затем про­суммировать полученные результаты. Этот процесс проиллюстрирован на рис. 2.4:

Рисунок 2.4 – Вычисление общей суммы продажи

Для выполнения обязанности, связанной со знанием и предоставлением промежуточной суммы, объекту SalesLineItem должна быть известна стои­мость товара.

В данном случае в качестве информационного эксперта будет выступать объект ProductSpecification.

Результаты проектирования представлены на рис. 2.5:

Рисунок 2.5 – Вычисление общей суммы продажи

Для выполнения обязанности "знать и предоставлять общую сумму продажи трем объектам классов" были следующим образом присвоены три обязанности.

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

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

Преимущества

    Шаблон Expertподдерживает инкапсуляцию. Для выполнения требуемых задач объекты используют собственные данные. Подобную возможность обеспечивает также шаблонLowCoupling, применение которого приводит к созданию более надежных и легко поддерживаемых систем.

    Соответствующее поведение системы обеспечивается несколькими классами, содержащими требуемую информацию. Это приводит к определениям клас­сов, которые гораздо проще понимать и поддерживать. Кроме того, поддер­живается шаблон HighCohesion.

Связанные шаблоны:

Другие названия и аналогичные принципы: "Хранение обязанностей вместе с дан­ными", "Кто знает, тот и выполняет", "Сделай сам", "Размещайте службы вме­сте с их атрибутами".

Шаблоны объектно-ориентированного проектирования GRASP February 8th, 2009

Current Mood: creative

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

GRASP - General Responsibility Assignment Software Patterns (основные шаблоны распределения обязанностей в программном обеспечении). Это методический подход к объектному проектированию. Эти шаблоны называют также шаблонами распределения обязанностей. Под "шаблоном" в данном контексте, да и в любом контексте, связанном с разработкой ПО, понимается именованная пара "проблема/решение", содержащая рекомендации для применения в различных конкретных ситуациях. Шаблоны GRASP относятся к этапу проектирования и отвечают за взаимосвязь объектов в системе. GRASP состоит из 5 основных и 4 дополнительных шаблонов.

Основные шаблоны:

    Information Expert

Дополнительные шаблоны:

    Pure Fabrication

  • Protected Variations

Information Expert

Шаблон решает проблему распределения обязанностей между объектами в объектно-ориентированной системе. Под обязанностью в контексте GRASP понимается некое действие (функция) объекта. Т.о. Information Expert дает рекомендации касательно того, какие функции должен выполнять тот или иной объект. А решение очень простое и понятное без доказательств: назначать обязанность следует информационному эксперту - классу, у которого имеется информация, требуемая для выполнения обязанности. Конечно, не всегда бывает так, что вся необходимая информация заключена в одном классе (это, кстати, идет в противоречие с паттерном High Cohesion, о котором позже), чаще она распределена между различными классами, тогда каждый из этих классов будет являться частичным экспертом, т.е. будет предоставлять только доступную ему информацию, а при общем взаимодействии будет решена общая задача.

Шаблон Creator решает проблему о том, кто должен создавать экземпляры новых классов. Решение состоит в назначении классу B обязанностей создавать экземпляры класса A, если выполняется одно из условий:

    Класс B агрегирует (aggregate) объекты A

    Класс B содержит (contains) объекты A

    Класс B записывает (records) экземпляры объектов A

    Класс B активно использует (closely uses) объекты A

    Класс B обладает данными инициализации (has the initializing data), которые будут передаваться объектам A при их создании (т.е. при создании объектов А класс В является экспертом)

Смысл паттерна снова интуитивно понятен, каждый разработчик использовал его, руководствуясь здравой логикой, сам того не осознавая. Тем не менее, за кажущейся простотой скрывается масса преимуществ: поддерживается шаблон Low Coupling, снижаются затрат на сопровождение и обеспечивается возможности повторного использования созданных компонентов в дальнейшем.

Controller

Шаблон сontroller решает давнюю проблему разделения интерфейса и логики в интерактивном приложении. Это не что иное, как C из аббревиатуры MVC. Этот шаблон отвечает за то, к кому именно должны обращаться вызовы из V (View), и кому C должен делегировать запросы на выполнение (какая модель M должна их обработать). Если обобщить назначение сontroller, то он должен отвечать за обработку входных системных сообщений. Под системными сообщениями здесь понимаются события высокого уровня, генерируемые внешним исполнителем. Чтобы решить поставленную проблему необходимо делегировать обязанности обработки системных сообщений классу, удовлетворяющему одному из следующих условий:

    Класс представляет всю систему в целом, устройство или подсистему (внешний контроллер)

    Класс представляет сценарий некоторого прецедента, в рамках которого выполняется обработка всех системных событий, и обычно называется <Прецедент>Handler, <Прецедент>Coordinator или <Прецедент>Session (контроллер прецедента или контроллер сеанса). Для всех системных событий в рамках одного сценария прецедента используется один и тот же класс-контроллер. Неформально, сеанс - это экземпляр взаимодействия с исполнителем. Сеансы могут иметь произвольную длину, но зачастую организованы в рамках одного прецедента (сеанса прецедента).

Как бы заумно не звучало все вышеперечисленное, на самом деле все предельно просто: контроллер это своеобразный вид интерфейса между уровнями предметной области и графического представления. Первым типом контроллеров является внешний контроллер (facade controller), представляющий всю систему, устройство или подсистему. Если применяется контроллер прецедента (use case controller), то для каждого прецедента должен существовать отдельный контроллер. Не объект предметной области, а искусственная конструкция.

Low Coupling

Шаблон решает проблему связности. Связность можно определить как количество точек соприкосновения классов между собой. Известно, что чем ниже связность классов, тем меньше их взаимовлияние, тем выше возможность повторного использования. А рекомендация здесь простая: распределять обязанности между классами надо таким образом, чтобы уменьшить связность.

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

Высокая степень связывания сама по себе не является проблемой. Проблемой является жесткое связывание с неустойчивыми в некотором отношении элементами.

High Cohesion

Шаблон решает общую проблему управления сложностью за счет регулирования степени зацепления классов. Разница между связностью и зацеплением очень тонка, и понять ее необходимо на более глубоком интуитивном уровне. Зацепление (cohesion) (или более точно, функциональное зацепление) - это мера связанности и сфокусированности обязанностей класса. Считается, что элемент обладает высокой степенью зацепления, если его обязанности тесно связаны между собой и он не выполняет огромных объемов работы. Класс с низкой степенью зацепления выполняет много разнородных функций или несвязанных между собой обязанностей.

High Cohesion твердит, что класс должен стараться выполнять как можно меньше не специфичных для него задач, и иметь вполне определенную область применения. Только с опытом приходит понимание балансировки между High Cohesion и Low Coupling. считается что связывание и зацепление это инь и янь проектирования ПО. Некорректное связывание порождает неправильное зацепление и наоборот.

Pure Fabrication

Формулировки и мотивации дополнительных шаблонов GRASP не так очевидны. И без примеров здесь трудно ориентироваться. Проблемой, решаемой Pure Fabrication, является обеспечение реализации шаблонов High Cohesion и Low Coupling или других принципов проектирования, если шаблон Expert (например) не обеспечивает подходящего решения. Решением может быть введение служебного класса, не представляющего понятия конкретной предметной области, однако имеющего высокую степень зацепления.

Например, классу X необходимо сохранять информацию в реляционной базе данных. Согласно шаблону Information Expert, эту обязанность можно присвоить самому классу X. Однако следует принять во внимание, что Данная задача требует достаточно большого числа специализированных операций, поэтому класс X будет иметь низкую степень зацепления, класс X будет связан с интерфейсом БД, что повысит связность, кроме того задача записи в БД является довольно общей, поэтому необходимо обеспечить повторное использование кода. Естественным решением данной проблемы является создание нового класса, ответственного за сохранение объектов некоторого вида на постоянном носителе, например в реляционной базе данных. Его можно назвать PersistentStorage. Это чисто синтетический объект, что полностью соответствует Pure Fabrication. В итоге решаются задачи зацепления, связности и повторного использования.

Indirection

Шаблон решает проблему прямой связности. Решением является введение промежуточного объекта для обеспечения связи между другими компонентами или службами, которые не связаны между собой напрямую.

Пример, рассмотренный выше, с введением класса PersistentStorage является также и примером шаблона Indirection, т.к. дополнительный класс будет являться промежуточным звеном между БД и классом X. Примерами специализированных вариантов Indirection являются шаблоны Adapter, Facade, Observer (см. шаблоны Gang of Four). Целью введения промежуточного звена является обеспечение слабой связности за счет отделения друг от друга различных компонентов.

Polymorphism

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

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

    Новые вариации можно вводить без модификации клиентской части приложения.

Protected Variations

Основная проблема, решаемая шаблоном Protected Variations: как спроектировать объекты, подсистемы и систему, чтобы изменение этих элементов не оказывало нежелательного влияния на другие элементы? необходимо идентифицировать точки возможных вариаций или неустойчивости; распределить обязанности таким образом, чтобы обеспечить устойчивый интерфейс. Шаблон PV описывает ключевой принцип, на основе которого реализуются механизмы и шаблоны программирования и проектирования с целью обеспечения гибкости и защиты системы от влияния изменений внешних систем.



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows