Нужен совет по дизайну POCO и использованию Lazy <> для новой архитектуры - PullRequest
2 голосов
/ 18 января 2012

Я столкнулся с архитектурными решениями, которые довольно сложно решить. Заранее прошу прощения за длинный пост, но прежде чем вы сможете мне помочь, я должен дать вам контекст.

Моя компания пытается интегрировать новую архитектуру (основанную на платформе ASP.NET MVC) в существующий устаревший код ASP.NET. Намек состоит в том, что мы не можем избавиться от всего бизнес-кода, который инкапсулирован в устаревших сборках, но мы должны обернуть его в новые, чтобы создать своего рода «антикоррупционный» слой и отделить его. Мы хороши до сих пор, но здесь есть одно ограничение (основное), которое делает разделение немного сложнее:

  1. На устаревшем веб-сайте ASP.NET они использовали своего рода модель с поддержкой персистентности, чтобы включить отложенную загрузку из представлений (я знаю, что это дерьмо). Для этого есть причина. Код настолько сложен и сложен в развертывании, что они хотели предоставить дизайнерам возможность изменять только представления без развертывания двоичных файлов. Класс God помещается в представление со свойствами, которые загружаются в случае необходимости. Так, например, если дизайнер хочет изменить представление, чтобы отобразить другое свойство, он может просто выбрать то, что ему нужно, из класса God, и это просто работает. Мы должны сохранить то же поведение в новой архитектуре MVC .

Давайте рассмотрим пример. Допустим, у нас есть Item наследие стойкий DTO:

public class Item
{
   public string Title {get; set; }
   public List<UserComment> Comments {get; set; } // lazy loaded in the background in legacy code.
}

Таким образом, дизайнер использует представление, может вызвать Item.Title и развернуть, а после может добавить, если хочет Item.Comments (в foreach), и развернуть только представление без необходимости развертывания всех двоичных файлов.

Была предложена следующая архитектура. Новые POCO для веб-сайта mvc находятся в сборке Domain, которая не относится ни к какой другой сборке. В этой сборке у нас также есть определение интерфейсов репозиториев, таких как IItemRepository. Сущности используются непосредственно в ASP.NET MVC ViewModels и получаются с помощью реализаций репозитория, которые подключены соответствующим контейнером DI.

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

До сих пор все отлично. Но вот сложная часть. Объекты из сборки домена должны соответствовать ограничению с точки 1 (ленивая загрузка в представлениях).

Таким образом, наши POCO объявляют все свойства как Lazy <>. Что позволяет нам в сборке реализации (той, которая ссылается на весь унаследованный код) определять делегатов, которые заполняют эти свойства при обращении к ним. Вот новая реализация POCO для MVC:

public class Item
    {
       public string Title {get; set; }
       public Lazy<List<UserComment>> Comments {get; set; } // lazy loaded in the background in legacy code.
    }

А вот реализация ItemRepository:

public class ItemRepository : IItemRepository
{
    public Item GetItem(int id) 
    {
        Item i = new Item() { Id = id };
        i.Comments = new System.Lazy<IEnumerable<UserComments>>( () => CommentsService.GetUserComments(id));

        return i;
    }
}

Нам это не очень нравится, и вот почему:

  • POCO на самом деле не POCO, потому что кажется, что у сущностей есть утечка абстракции управления жизненным циклом. Это не имеет большого значения, потому что Lazy <> - это тип в .NET Framework. С другой стороны, если вы используете ORM, такой как NHibernate, вы должны согнуть свои POCO, чтобы позволить NHibernate загружать данные (специальный конструктор, виртуальные члены и т. Д.)
  • Другая причина, по которой нам это не нравится, заключается в том, что он скрывает базовую структуру сервиса в реализации репозиториев. Например, если используется Item.Comments, в базовой реализации ItemRepository мы будем вызывать другую унаследованную службу (в этом случае CommentsService.GetUserComments (id)) *

Вопрос 1: Видите ли вы другие недостатки в использовании Lazy <> в реализации POCO? Или другие недостатки в дизайне, которые мы должны рассмотреть?

Вопрос 2: Как мы можем избежать унаследованного состава служб в реализациях репозитория, чтобы иметь четкое «видение» того, какие унаследованные сервисы используются? Кроме того, нам действительно нужно это "видение" на уровне реализации, как мы могли бы рассмотреть хранилищареализация как «фасад» для устаревших услуг?

Вопрос 3: Существуют ли другие альтернативы в отношении ограничения 1 (ленивая нагрузка)?

Вопрос 4: Существуют ли какие-либо рекомендации, касающиеся состава для ленивых членов?

Прошу прощения за длинные вопросы, но буду очень признателен за вашу помощь.

Thomas

1 Ответ

2 голосов
/ 18 января 2012

Должны ли свойства отложенной загрузки быть List<T>? Если нет, вы можете определить их как IList<T> или ICollection<T>, например:

public class Item
{
   public string Title {get; set; }
   public IList<UserComment> Comments {get; set; }
}

Теперь, поскольку свойство является экземпляром интерфейса, вы можете создать из него виртуальный прокси.

...