Presentation is loading. Please wait.

Presentation is loading. Please wait.

ORM Паттерны. Repository Repository (хранилище) ― выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в.

Similar presentations


Presentation on theme: "ORM Паттерны. Repository Repository (хранилище) ― выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в."— Presentation transcript:

1 ORM Паттерны

2 Repository Repository (хранилище) ― выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в виде коллекции для доступа к объектам домена.

3 Пример Обратимся к упомянутому ранее примеру на NHibernate. Пусть у нас определн класс автора: public class Author { public virtual int Id { get; set; } public virtual string FirstName { get; set; } public virtual string LastName { get; set; } public virtual int YearOfBirth { get; set; } public virtual Iesi.Collections.Generic.ISet Books { get; set; } }

4 Пример Файл, который отображает класс автора на таблицу БД: <property name="YearOfBirth" type="System.Int32" column="YearOfBirth"/> <many-to-many class ="Books.Domain.Book, NHibernateDemo" column="BookId">

5 Пример Пусть нам необходимо заполнить выпадающий список именами авторов, скажем, для того чтобы впоследствии вывести список всех его работ: public void FillAuthorsComboBox(ComboBox comboBox, ISessionFactory factory) { ISession session = factory.OpenSession(); try { IQuery authorsQuery = session.CreateQuery("FROM Author"); IList authors = authorsQuery.List (); foreach (Author author in authors) comboBox.Items.Add(author.LastName + ", " + author.FirstName); } finally { session.Close(); }}}}

6 Пример Пусть одной из функций нашего приложения является вывод информации о всех авторах в формате HTML: public string GetAllAuthorsAsHTML(ISessionFactory factory) { ISession session = factory.OpenSession(); try { IQuery authorsQuery = session.CreateQuery("FROM Author"); IList authors = authorsQuery.List (); StringBuilder result = new StringBuilder(); result.Append(" ").Append(" "); foreach (Author author in authors) { result.Append(" ").Append(author.LastName + ", " + author.FirstName).Append(" "); result.Append(" Year of birth: ").Append(author.YearOfBirth.ToString()).Append(" "); } result.Append(" ").Append(" "); return result.ToString(); } finally { session.Close(); }}}}

7 Пример Недостатки использованного подхода: неоправданное дублирование; зависимость от конкретной реализации ORM; непрозрачность кода; невозможность протестировать код.

8 Схема

9 Пример Определим класс Repository: public class Repository { private ISession session; public Repository(ISession session) { this.session = session; } public IEnumerable GetAllAuthors() { IQuery authorsQuery = session.CreateQuery("FROM Author"); return authorsQuery.List (); }}}}

10 Пример Теперь функции, которые работают со списком авторов, можно переписать следующим образом: public void FillAuthorsComboBox( ComboBox comboBox, Repository repository) { IEnumerable authors = repository.GetAllAuthors(); foreach (Author author in authors) comboBox.Items.Add( author.LastName + ", " + author.FirstName); }

11 Пример Функция экспорта в HTML преобразуется следующим образом: public string GetAllAuthorsAsHTML(Repository repository) { IEnumerable authors = repository.GetAllAuthors(); StringBuilder result = new StringBuilder(); result.Append(" ").Append(" "); foreach (Author author in authors) { result.Append(" ").Append(author.LastName + ", " + author.FirstName).Append(" "); result.Append(" Year of birth: ").Append(author.YearOfBirth.ToString()).Append(" "); } result.Append(" ").Append(" "); return result.ToString(); }

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

13 Specification Specification (спецификация) ― паттерн, который инкапсулирует логику отбора доменных объектов в отдельный объект.

14 Specification

15 Specification. Пример Предположим, что нам необходимо делать выборки авторов, удовлетворяющие разным критериям. Например, выбирать авторов, родившихся в определнный период или имя которых содержит заданное значение: public class Repository { public IEnumerable FindAuthors_BornBetween(int startYear, int endYear) { return session.QueryOver ().Where(a => a.YearOfBirth >= startYear && a.YearOfBirth (); } public IEnumerable FindAuthors_NameContains(string value) { return session.QueryOver ().Where(a => a.FirstName.Contains(value)).List (); }}}} Интерфейс класса Repository может стать неоправданно большим. Кроме того, такая реализация нарушает принцип открытости/закрытости.

16 Specification. Пример Решением является использование паттерна Спецификация. Рассмотрим пример применения данного паттерна: public interface ISpecification { Expression > IsSatisfiedBy(); } public class Repository { public IEnumerable FindAuthors( ISpecification specification) { return session.QueryOver ().Where(specification.IsSatisfiedBy()).List (); }}}}

17 Specification. Пример Класс, реализующий интерфейс спецификации и выполняющий проверку даты рождения на вхождение в определнный диапазон, будет выглядеть так: public class IsYearOfBirthInRange : ISpecification { private int endYear; private int startYear; public IsYearOfBirthInRange(int startYear, int endYear) { this.startYear = startYear; this.endYear = endYear; } public Expression > IsSatisfiedBy() { return author => author.YearOfBirth >= startYear && author.YearOfBirth <= endYear; }}}}

18 Specification. Пример Класс, реализующий интерфейс спецификации и анализирующий имя автора, будет следующим: public class AuthorNameContains : ISpecification { private string value; public AuthorNameContains(string value) { this.value = value; } public Expression > IsSatisfiedBy() { return author => author.FirstName.Contains(value); }}}}

19 Specification. Пример Рассмотрим теперь пример использования полученных классов. Выведем всех авторов, родившихся во второй половине XX века: public void DisplayAuthors(Repository repository) { IEnumerable authors = repository.FindAuthors(new IsYearOfBirthInRange(1950, 2000)); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }

20 Specification Для того чтобы сделать выборку, удовлетворяющую нескольким условиям, можно применить паттерны компоновщик и декоратор следующим образом:

21 Specification Интерфейс спецификации следует расширить следующим образом: public interface ISpecification { Expression > IsSatisfiedBy(); ISpecification Or(ISpecification left); ISpecification And(ISpecification left); ISpecification Not(); }

22 Specification Класс составного условия будет следующим: public abstract class CompositeSpecification : ISpecification { public abstract Expression > IsSatisfiedBy(); public ISpecification Or(ISpecification right) { return new OrSpecification (this, right); } public ISpecification And(ISpecification right) { return new AndSpecification (this, right); } public ISpecification Not() { return new NotSpecification (this); }}}}

23 Specification Рассмотрим реализацию наследников упомянутого выше класса. Класс AndSpecification будет следующим: public class AndSpecification : CompositeSpecification { private ISpecification left; private ISpecification right; public AndSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.And( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

24 Specification Класс OrSpecification: public class OrSpecification : CompositeSpecification { private ISpecification left; private ISpecification right; public OrSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.Or( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

25 Specification Класс NotSpecification: public class NotSpecification : CompositeSpecification { private ISpecification wrapped; public NotSpecification(ISpecification wrapped) { this.wrapped = wrapped; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.Not(wrapped.IsSatisfiedBy())); }}}}

26 Specification Теперь классы конкретных условий должны наследовать класс CompositeSpecification: public class IsYearOfBirthInRange : CompositeSpecification { private int endYear; private int startYear; public IsYearOfBirthInRange(int startYear, int endYear) { this.startYear = startYear; this.endYear = endYear; } public override Expression > IsSatisfiedBy() { return author => author.YearOfBirth >= startYear && author.YearOfBirth <= endYear; }}}}

27 Specification Рассмотрим пример использования. Выберем всех авторов, которые родились не в первой половине XX века и имя которых содержит букву «А»: public static void DisplayAuthors(Repository repository) { ISpecification condition = ( (new IsYearOfBirthInRange(1950, 1999)).Not() ).And ( new AuthorNameContains("A") ); IEnumerable authors = repository.FindAuthors(condition); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }

28 Specification Такая возможность языка C# 3.0, как методы расширения позволяет реализовать подобную функциональность следующим образом: public static class SpecificationUtils { public static ISpecification Or (this ISpecification left, ISpecification right) { return new OrSpecification (left, right); } public static ISpecification And (this ISpecification left, ISpecification right) { return new AndSpecification (left, right); } public static ISpecification Not (this ISpecification wrapped) { return new NotSpecification (wrapped); }}}}

29 Specification Класс AndSpecification будет выглядеть так: Остальные подобные классы реализуются аналогично. public class AndSpecification : ISpecification { private ISpecification left; private ISpecification right; public AndSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.And( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

30 Specification Клиентский код остатся без изменений: public static void DisplayAuthors(Repository repository) { ISpecification condition = ( (new IsYearOfBirthInRange(1950, 1999)).Not() ).And ( new AuthorNameContains("A") ); IEnumerable authors = repository.FindAuthors(condition); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }


Download ppt "ORM Паттерны. Repository Repository (хранилище) ― выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в."

Similar presentations


Ads by Google