Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

3.2 Базовые типовые решения

Лекция



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

3.2.1    Паттерт Layer Supertype

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

Принцип действия

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

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

Назначение

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

3.2.2    Паттерн Separated Interface

Отделенный интерфейс (Separated Interface). Предполагает размещение интерфейса и его реализации в разных пакетах.

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

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

Принцип действия

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

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

Интерфейс можно поместить в пакет клиента или же в отдельный пакет. Если реализация имеет только одного клиента или все клиенты реализации находятся в одном пакете, интерфейс может быть размещен прямо в пакете клиента. В связи с этим нелишне задуматься о том, отвечают ли разработчики клиентского пакета за определение интерфейса? Размещение интерфейса в пакете клиента указывает на то, что данный пакет будет принимать обращения от всех пакетов, содержащих реализацию этого интерфейса. Таким образом, если у вас есть несколько клиентских пакетов, интерфейс лучше поместить в отдельный пакет (см. рис. 3.1). Это рекомендуется делать и тогда, когда определение интерфейса не входит в обязанности разработчиков        клиентского пакета  (например,  когда определением интерфейса занимаются разработчики его реализации).

 3.2      Базовые типовые решения

 

Рисунок 3.1 Размещение интерфейса в отдельном пакете

Помимо всего прочего,  разработчику отделенного интерфейса необходимо выбрать,  какими средствами языка программирования следует воспользоваться для описания интерфейса Складывается впечатление, что при использовании языков наподобие Java и С#, содержащих специальные интерфейсные конструкции, проще всего применить ключевое слово interface. Как ни странно, это далеко не всегда удачный выбор. Часто в качестве интерфейса лучше использовать абстрактный класс, чтобы допустить наличие общего, но необязательного поведения.

Наиболее неприятным моментом в использовании отделенного интерфейса является создание          экземпляра            реализации.  Как         правило,  чтобы создать         экземпляр        реализации,  объект должен "знать" о классе последней. Зачастую в качестве такого объекта применяют отдельный объект-фабрику  (factory  object),  интерфейс которого также реализован в виде отделенного интерфейса. Разумеется,  объект-фабрика должен зависеть от реализации интерфейса, поэтому для обеспечения наиболее "безболезненной" связи применяют дополнительный модуль. Последний не только обеспечивает отсутствие зависимостей, но

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

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

Назначение

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

  • Если вы разместили в пакете инфраструктуры абстрактный код для обработки стандартных случаев, который должен вызывать конкретный код приложения.
  • Если код одного слоя приложения должен обратиться к коду другого слоя, о суще ствовании которого он не знает (например, когда код домена обращается к преоб разователю данных.
  • Если нужно вызвать методы, разработанные кем-то другим, но вы не хотите, что бы ваш код зависел от интерфейсов API этих разработчиков.

3.2.3    Паттерн Lazy Load

Загрузка по требованию (Lazy Load) Объект, который не содержит все требующиеся данные,  однако может загрузить их в случае необходимости.

 3.2      Базовые типовые решения

 

Рисунок 3.2. Загрузка данных по требованию (пример)

 

Загрузку данных в оперативную память следует организовать таким образом,  чтобы при загрузке интересующего вас объекта из базы данных автоматически извлекались и другие связанные с ним объекты. Об этом говорит сайт https://intellect.icu . Это значительно облегчает жизнь разработчика, которому в противном случае пришлось бы прописывать загрузку всех связанных объектов вручную.

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

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

Принцип действия

Существует несколько способов реализации загрузки по Самый простой из них - инициализация по требованию. Основная идея данного           подхода заключается в том,  что при каждой попытке доступа       к полювыполняется проверка,  не содержит ли оно значение         NULL. ЕСЛИ  поле содержит NULL, метод доступа            загружает            значение поля и лишь затем его возвращает.  Это может быть реализовано только в том случае, если поле является самоинкапсулированным, т.е. если доступ к такому полю осуществляется только п средством  get-метода  (даже в пределах самого класса).

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

Назначение

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

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

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

3.2.4    Паттерн Record Set

Множество записей (Record Set). Представление табличных данных в оперативной памяти.

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

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

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

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

Принцип действия

Обычно множество записей не приходится конструировать самому. Как правило, подобные классы прилагаются к используемой программной платформе. В качестве примера можно привести объекты DataSet библиотеки ADO.NET и объекты RowSet библиотеки JDBС.

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

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

При работе с множеством записей очень важно, чтобы последнее было легко отсоединить от источника данных. Это позволяет передавать множество записей по сети, не беспокоясь о наличии соединения с базой данных.  Необходимость отсоединения приводит к очевидной проблеме: как выполнять обновление множества записей? Все больше и больше платформ реализуют множество заиписей в виде единицы работы (Unit of Work,), благодаря чему все изменения множества записей могут быть внесены в отсоединенном режиме и затем зафиксированы в базе данных.

Явный интерфейс

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

tion ["passenger"]. Применение явного интерфейса требует реализации отдельного класса  Reservation  с конкретными методами и атрибутами,  а извлечение сведений о пассажире выполняется с помощью выражений типа aReservation. passenger.

Неявные интерфейсы обладают чрезвычайной гибкостью. Универсальное множество записей может быть использовано для любых видов данных, что избавляет от необходимости написания нового класса при определении каждого нового типа множества записей.  Несмотря на подобные преимущества, неявные интерфейсы являются весьма спорным решением. Как узнать, какое слово нужно использовать для того, чтобы добраться к сведениям о пассажире,  забронировавшем билет,  - "passenger"  ("пассажир"),  "guest" ("клиент") или, может быть, "flyer" ("летящий")? Единственное, что можно сделать, - это "прочесать" весь исходный код приложения в поисках мест, где создаются и используются объекты бронирования. Если же у меня есть явный интерфейс, мы можем открыть определение класса Reservation и посмотреть, какое свойство нужно.

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

 

((Person) aReservation["passenger"]).lastNameж

 

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

 

aReservation.passenger.lastName.

 

В библиотеке ADO.NET возможность применения явного интерфейса обеспечивают строго типизированные объекты  DataSet  - сгенерированные классы,  которые предоставляют явный иполностью типизированный интерфейс к множеству записей. Поскольку объект DataSet  может содержать в себе множество таблиц и отношений, в которых они находятся, строго типизированные объекты DataSetвключают в себя свойства, использующие информацию об отношениях между таблицами. Генерация классов DataSet  выполняется на основе определений схем XML (XML Schema Definition — XSD).

3.2.5    Паттерн Unit of Work

Единица работы (Unit of Work). Содержит список объектов, охватываемых бизнес-транзакцией, координирует запись изменений в базу данных и разрешает проблемы параллелизма.

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

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

Принцип действия

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

Когда вы решаете зафиксировать сделанные изменения, единица работы определяет,  что ей нужно сделать.  Она сама открывает транзакцию,  выполняет всю необходимую проверку на наличие параллельных операций (с помощью пессимистической автономной блокировки  (Pessimistic  Offline  Lock  [4])  или оптимистической автономной      блокировки (Optimistic Offline Lock [4])) и записывает изменения в базу данных. Разработчики приложений никогда явно не вызывают       методы,  выполняющие обновления базы данных. Таким образом, им не приходится отслеживать, что было изменено, или беспокоитьсяо том, в каком порядке необходимо выполнить нужные действия, чтобы не нарушить целостность на уровне ссылок, - единица работы сделает это за них.

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

Назначение

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

 3.2      Базовые типовые решения

 

Рисунок 3.3 Регистрация изменяемого объекта

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

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

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

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

Особенность .NET реализации

В  .NET для реализации единицы работы используется объект  DataSet, лежащий в основе отсоединенной модели доступа к данным. Последнее обстоятельство         немного           отличает его   от        остальных       разновидностей     шаблона. В среде .NET  данные загружаются из базы данных в объект DataSet, дальнейшие изменения которого происходят в автономном режиме. Объект DataSet состоит из таблиц (объекты DataTable), которые, в свою очередь, состоят из столбцов (объекты DataColumn)  и строк  (объекты  DataRow).  Таким   образом,  объект  DataSet  представляет собой "зеркальную" копию множества данных, полученного в результате выполнения одного или нескольких  SQL-запросов. У каждой    строки DataRow есть  версии   (Current,  Original,  Proposed)             и          состояния (Unchanged,  Added,  Deleted,  Modified).  Наличие   последних,  а   также  тот факт, что объектная модель DataSet в точности повторяет структуру базы данных, значительно упрощает запись изменений обратно в базу данных.

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

создано: 2014-10-05
обновлено: 2021-01-10
132519



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


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

Объектно-ориентированное программирование ООП

Термины: Объектно-ориентированное программирование ООП