Bussiness Entity, Component and DAL
От: alastochkin Россия  
Дата: 27.02.07 21:29
Оценка:
Добрый день, друзья.

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

Я использую custom entities (т.е. не DataSet'ы, а свои классы, см. пример кода ниже). Если я выделяю DAL в отдельную сборку, я не могу поместить ссылку на BLL, т.к. circular reference. Поэтому для того, чтобы я мог получить доступ из DAL к объектам бизнес логики мне нужно еще создать IPerson (куда вытащить все property Person, которые используются из DAL) и сделать Factory для Person, чтобы в DAL можно было создавать экземпляр Person.

Поэтому получается, для одного класса Person, мне нужно сделать как минимум 4 класса: BLL.Person, IDAL.Person, Model.IPerson, DAL.Person. Что получается слишком громоздко. И тем более, если в BLL.Person я получаю список, мне нужно будет каждый IPerson кастить в Person, что не совсем удобно.

Вопрос 1: Как обычно решается подобная проблема?

Читал статью Application Architecture for .NET: Designing Applications and Services.
Вопрос 2: Подскажите чем Business Entity отличается от Business Component.

Недавно просматривал книгу Applying Domain-Driven Design and Patterns, и как я понял автор предлагает разделять классы Domain (состояние) и Business Logic (поведение). Мало того, говорит что классы Business Logic можно делать статическими, содержащими одни только методы, которые принимают экземпляр класса как аргумент, например static OrderManager.Save(Order order), а не Order.Save().

Вопрос 3: Правильно ли я думаю, что Business Entity это синоним Domain?

Не могу понять такой подход. Вопрос 4: Проясните пожалуйста как подобную вещь с наследованием (см. ниже) сделать на Domain-Driven Design?:

/// BLL
enum PersonKind
{
   Student,
   Professor
}

abstract class Person
{
    public Guid Id;
    public string UserName;
    public abstract PersonKind Kind { get; } // хранится в базе, при вытаскивании записи - создается нужный класс

    public void Register()
    {
        IDAL.Save(this); // IDAL - для простоты. Объект реализующий IDAL.Person и содержащий методы DAL
        OnRegister();
    }

    protected abstract OnRegister();

    // вызывается из базы
    public static GetInstance(PersonKind kind)
    {
         if (kind == PersonKind.Professor) return new ProfessorPerson();
         else return new StudentPerson();
    }
}

class ProfessorPerson : Person
{
    protected override PersonKind Kind { get { return PersonKind.Professor; } }

    public string Subject; // некое дополнительное проперти только для Professor'а
    
    // просто кастомная логика, показать, что ProfessorPerson и StudentPerson ведуть себя по-разному
    // таких функций может быть много и у них логика будет сложнее.
    protected override void OnRegister
    { 
        RegisterNewEmployee();
        ScheduleManager.RecalculateSubject(Subject);     
    }

    private void RegisterNewEmployee() { ... }
}
Re: Bussiness Entity, Component and DAL
От: IB Австрия http://rsdn.ru
Дата: 27.02.07 22:27
Оценка: +1
Здравствуйте, alastochkin, Вы писали:

A> Если я выделяю DAL в отдельную сборку,

А для чего ты это делаешь?

A>Вопрос 1: Как обычно решается подобная проблема?

По разному...
1. Не выносят DAL в отдельную сборку. Сборка — это единица развертывания, а на практике развертывать DAL отдельно от BLL приходится редко. (Специально для педантов и зануд замечу, что это вовсе не означает отказ от разделения на DAL и BLL ).
2. Делают бизнес-сущности не зависимыми ни от чего, и вынеся их в отдельную сборку, можно использовать их и в BLL и в DAL сборках.
3. (Правильный =) ) Использовать одновременно первый и второй подход..

A>Недавно просматривал книгу Applying Domain-Driven Design and Patterns, и как я понял автор предлагает разделять классы Domain (состояние) и Business Logic (поведение). Мало того, говорит что классы Business Logic можно делать статическими, содержащими одни только методы, которые принимают экземпляр класса как аргумент, например static OrderManager.Save(Order order), а не Order.Save().

Умница, толковая должно быть книга... =)

A>Не могу понять такой подход. Вопрос 4: Проясните пожалуйста как подобную вещь с наследованием (см. ниже) сделать на Domain-Driven Design?:

Зачем Register(), OnRegister(), GetInstance и Kind нужны в Person?
Мы уже победили, просто это еще не так заметно...
Re[2]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 27.02.07 23:11
Оценка: +1
A>> Если я выделяю DAL в отдельную сборку,
IB>А для чего ты это делаешь?
Для написания еще одного DAL. Борьба мнений. Лично я не люблю особо закладываться наперед, т.к. это усложняет логику и порождает лишний код (но не исключаю держать это в уме). Но в команде есть мнение — что это облегчит перенос системы на другие базы данных, теоретически, чтобы добиться этого нужно будет написать еще один DAL и изменить в config'е имя DAL сборки .

A>>Вопрос 1: Как обычно решается подобная проблема?

IB>По разному...
IB>1. Не выносят DAL в отдельную сборку. Сборка — это единица развертывания, а на практике развертывать DAL отдельно от BLL приходится редко. (Специально для педантов и зануд замечу, что это вовсе не означает отказ от разделения на DAL и BLL ).
IB>2. Делают бизнес-сущности не зависимыми ни от чего, и вынеся их в отдельную сборку, можно использовать их и в BLL и в DAL сборках.
IB>3. (Правильный =) ) Использовать одновременно первый и второй подход..
Вот так и было, мы делали отдельные бизнес-сущности, у нас они назывались "Info-классы", т.е. классы, содержащие только данные, но не обладающие поведением. Только в этом случае не всегда было понятно, какие методы делать в Info-классе, а какие в BLL. Например, если есть ProductCost и DeliveryCost, и нужно добавить вычисляемое свойство TotalCost, не понятно в какой слой его надо помещать, теоретически это нужно делать в BLL статическим методом static OrderManager.GetTotalSum(Order order) { return order.RegionSum + order.PersonSum; }, но это же криво выглядит. И в результате того, что некоторые функции определены в Model, а некоторые в BLL — логика приложения размазывается.

Причина номер 2: Model.Person и BLL.Person это абсолютно разные классы, т.е. фактически нарушается инкапсуляция, т.к. защищенные члены просто отсутствуют — в Model.Person они просто не нужны, т.к. он не может содержать логики, а BLL.Person не содержит состояния.

Причина номер 3: наследование (см. ниже)

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

A>>Не могу понять такой подход. Вопрос 4: Проясните пожалуйста как подобную вещь с наследованием (см. ниже) сделать на Domain-Driven Design?:

IB>Зачем Register(), OnRegister(), GetInstance и Kind нужны в Person?
А как можно сделать иначе, если OnRegister для каждого типа Person может быть свой?
По идее можно вводить параллельную псевдо-иерархию (без наследования) вида:

static class BLL.Person, 
   static class BLL.ProfessortPerson
   static class BLL.StudentPerson

Но как тогда вызывать виртуальный метод OnRegister?
Re[3]: Bussiness Entity, Component and DAL
От: Trean Беларусь http://axamit.com/
Дата: 28.02.07 00:17
Оценка:
Здравствуйте, Andrey Lastochkin, Вы писали:

А почему бы не подсмотреть как это сделано в ORM средствах ((N)Hibernate, JDO)? Там люди уже продумали многие тонкие моменты.
Если нельзя использовать ORM, то лично я выбираю DAO + POJO (Data Objects). DAO состоит из интерфейса и реализации методов доступа к DB, и POJO класс+интерфейс, если мне нужно гарантировать, что класс не будет изменяться за пределами того места где он инициализируется (т.е. только accessors методы в интерфейсе). От приведения типа не спасет конечно, но его как раз можно отследить средствами IDE. Можно и без интерфейса обойтись.
Re[3]: Bussiness Entity, Component and DAL
От: IT Россия linq2db.com
Дата: 28.02.07 04:06
Оценка: 21 (1)
Здравствуйте, Andrey Lastochkin, Вы писали:

IB>>А для чего ты это делаешь?

AL>Для написания еще одного DAL.

Для этого тоже не всегда обязательно выносить DAL в отдельную сборку. Как уже сказал Иван, при разделении на сборки нужно руководствоваться соображениями развёртывания.

AL>Вот так и было, мы делали отдельные бизнес-сущности, у нас они назывались "Info-классы", т.е. классы, содержащие только данные, но не обладающие поведением. Только в этом случае не всегда было понятно, какие методы делать в Info-классе, а какие в BLL.


Если логика не цепляет что-то извне, например тот же BLL, то можно оставлять такую логику в объекте. Иначе всё в BLL.

AL>Например, если есть ProductCost и DeliveryCost, и нужно добавить вычисляемое свойство TotalCost, не понятно в какой слой его надо помещать, теоретически это нужно делать в BLL статическим методом static OrderManager.GetTotalSum(Order order) { return order.RegionSum + order.PersonSum; }, но это же криво выглядит.


Нормально выглядит. Гораздо хуже выглядят проблемы изначального вопроса.

AL>И в результате того, что некоторые функции определены в Model, а некоторые в BLL — логика приложения размазывается.


То что размазывается — это конечно плохо. Но давай вот такой пример. Что если для вычсления total нужно сходит за дополнительными данными в БД. В этом случае где лучше размещать такую логику: только на клиенте (не получится), только в BLL (тоже не получится), в DAL (как к ней обратиться минуя BLL) или вообще в сохранённой процедуре? На практике получается, что бизнес-логика по-любому размазывается по всему приложению, по-этому бороться с этим не нужно. Нужно это возглавить и организовать.

AL>Причина номер 2: Model.Person и BLL.Person это абсолютно разные классы, т.е. фактически нарушается инкапсуляция, т.к. защищенные члены просто отсутствуют — в Model.Person они просто не нужны, т.к. он не может содержать логики, а BLL.Person не содержит состояния.


И в чём проблема?

AL>Причина номер 3: наследование (см. ниже)


Наследование вполне можно использовать в объектной модели. Тоже не пойму проблему.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 28.02.07 06:28
Оценка:
AL>>Для написания еще одного DAL.
IT>Для этого тоже не всегда обязательно выносить DAL в отдельную сборку. Как уже сказал Иван, при разделении на сборки нужно руководствоваться соображениями развёртывания.
Да, понимаю. Ну т.е. получается что BLL и DAL нужно объединить в одну сборку.
Фактически весь проект, со всеми слоями можно засунуть в одну сборку, В отдельных сборках только поместить расширения для системы — plugins. Только нормально ли это если проект не маленький?

AL>>И в результате того, что некоторые функции определены в Model, а некоторые в BLL — логика приложения размазывается.

IT>То что размазывается — это конечно плохо. Но давай вот такой пример. Что если для вычсления total нужно сходит за дополнительными данными в БД. В этом случае где лучше размещать такую логику: только на клиенте (не получится), только в BLL (тоже не получится), в DAL (как к ней обратиться минуя BLL) или вообще в сохранённой процедуре? На практике получается, что бизнес-логика по-любому размазывается по всему приложению, по-этому бороться с этим не нужно. Нужно это возглавить и организовать.
Ну, в своем видении системы, я бы сделал это свойством определенно в одном классе Order, в этом случае, не приходилось бы думать содержит оно внутри логику для работы с БД или нет и где оно в OrderManager или в OrderInfo

AL>>Причина номер 2: Model.Person и BLL.Person это абсолютно разные классы, т.е. фактически нарушается инкапсуляция, т.к. защищенные члены просто отсутствуют — в Model.Person они просто не нужны, т.к. он не может содержать логики, а BLL.Person не содержит состояния.

IT>И в чём проблема?
Ну некрасиво как-то, нестройно

AL>>Причина номер 3: наследование (см. ниже)

IT>Наследование вполне можно использовать в объектной модели. Тоже не пойму проблему.
Очень интересует, как можно метод сделать виртуальным (тот же Register)? Можно на примере кода, с которого я начинал тему.

Я это обходил так, вводил параллельную иерархию и методы, работающие с самим экземпляром, делал нестатическими. Получалась параллельная иерархия вида
PersonManager, ProfessorPersonManager : PersonManager, StudentPersonManager : PersonManager.
И делал экземлярное поле private xxxPersonManager _info.

Вызывал методы примерно так: PersonManager.GetInstance(person).Register().
В PersonManager.GetInstance в зависимости от типа person создавался соответствующий ему xxxPersonManager. Т.е. фактически, что можно было делать тремя классами приходилось делать шестью. И мне это очень не нравилось, как только я отошел от этой архитектуры, мне показалось что все стало на места.

Не могу понять, почему бизнес логику и бизнес сущность нужно разделять? Для чего и в чем это помогает?
Re[4]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 28.02.07 06:42
Оценка:
T>А почему бы не подсмотреть как это сделано в ORM средствах ((N)Hibernate, JDO)? Там люди уже продумали многие тонкие моменты.
T>Если нельзя использовать ORM, то лично я выбираю DAO + POJO (Data Objects).
T>DAO состоит из интерфейса и реализации методов доступа к DB
Как я понял это IDAL, о котором я говорил выше?

T> и POJO класс+интерфейс

Т.е. тот же BLL.Person и Model.IPerson?

T> если мне нужно гарантировать, что класс не будет изменяться за пределами того места где он инициализируется (т.е. только accessors методы в интерфейсе). От приведения типа не спасет конечно, но его как раз можно отследить средствами IDE. Можно и без интерфейса обойтись.

А, фабрику как делаешь в этом случае? Для каждого класса в конфиге прописываешь, или может быть пишешь некий алгоритм формирования имя типа и придерживаешься жесткого правила именования.

PS: я использую BLToolkit, но от DALа полностью не уйти, т.к. из хранимок возвращаются порой сложные структуры, которые без дополнительного маппинга не вернешь.
Еще, специально для интерфейсных нужд я выделяю часть DALUI который находится в DAL и вызывается напрямую из UI. Например, для получения постраничных выборок, сортировок, подсчета количества документов, возвращение малого количества полей из связанных сущностей, вместо создания множества непроинициализированных объектов.
Это либо конкретные UIEntity (стараюсь чтобы их было как можно меньше), либо DataTable/DataSet.
Re[3]: Bussiness Entity, Component and DAL
От: IB Австрия http://rsdn.ru
Дата: 28.02.07 08:12
Оценка:
Здравствуйте, Andrey Lastochkin, Вы писали:

AL>Для написания еще одного DAL.

На практике такое случается крайне редко, обычно DAL просто рефакторят...

AL> Но в команде есть мнение — что это облегчит перенос системы на другие базы данных, теоретически, чтобы добиться этого нужно будет написать еще один DAL и изменить в config'е имя DAL сборки .

Сейчас опять в апломб сорвусь.. Работа с разными БД — это утопия, если поддерживать их в серьез.
Опять-таки, если вдруг (упаси байт) вы в это впряжетесь, то при использовании подхода N3 вынести DAL в отдельную сборку будет задачей на пол-дня, включая тестирование.

AL> Только в этом случае не всегда было понятно, какие методы делать в Info-классе, а какие в BLL.

Все очень просто. В "Info" классе вообще не должно быть методов.

AL> теоретически это нужно делать в BLL статическим методом static OrderManager.GetTotalSum(Order order) { return order.RegionSum + order.PersonSum; }, но это же криво выглядит.

Кто сказал?

AL>Причина номер 2: Model.Person и BLL.Person это абсолютно разные классы,

Угу.

AL> т.е. фактически нарушается инкапсуляция,

Нет, не нарушается. Что там инкапсулировать в данных? Вот логику имеет смысл но там она и так инкапсулирована в полный рост.

AL> т.к. защищенные члены просто отсутствуют — в Model.Person они просто не нужны, т.к. он не может содержать логики, а BLL.Person не содержит состояния.

Именно.

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

Сомневаюсь, обычно получается наоборот.

AL>А как можно сделать иначе, если OnRegister для каждого типа Person может быть свой?

А перегрузка уже не работает?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[4]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 28.02.07 08:48
Оценка:
AL>>Для написания еще одного DAL.
IB>На практике такое случается крайне редко, обычно DAL просто рефакторят...
У нас в проекте есть несколько мест, где составляется динамический запрос и от него не уйти.
По идее можно наверное это засунуть в промежуточный XML, чтобы потом в хранимке его как-то хитро распарсить, но это весьма геморно.

AL>> Но в команде есть мнение — что это облегчит перенос системы на другие базы данных, теоретически, чтобы добиться этого нужно будет написать еще один DAL и изменить в config'е имя DAL сборки .

IB>Сейчас опять в апломб сорвусь.. Работа с разными БД — это утопия, если поддерживать их в серьез.
IB>Опять-таки, если вдруг (упаси байт) вы в это впряжетесь, то при использовании подхода N3 вынести DAL в отдельную сборку будет задачей на пол-дня, включая тестирование.
Не тянет на полдня, нужно сгенерить IDAL.Person, создать интерфейсы Model.IPerson и забабахать еще фабрику для создания Person.

AL>>А как можно сделать иначе, если OnRegister для каждого типа Person может быть свой?

IB>А перегрузка уже не работает?
Я просто не понимаю как вы обычно реализовываете это, тем более если речь идет о статическом методе OnRegister.

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

PS: любые толковые ссылки относящиеся к этой теме приветствуются.
Re[5]: Bussiness Entity, Component and DAL
От: IB Австрия http://rsdn.ru
Дата: 28.02.07 09:04
Оценка:
Здравствуйте, Andrey Lastochkin, Вы писали:

AL>Фактически весь проект, со всеми слоями можно засунуть в одну сборку, В отдельных сборках только поместить расширения для системы — plugins. Только нормально ли это если проект не маленький?

В принципе нормально. Но я в своих проектах обычно делю на сборки "вертикально", по компонентам. Например, отдельная сборка — работа с пользователями, включая DAL, BLL и BizEntity, отдельная сборка — продукты и их иерархия (эти две сборки ничего друг о друге не знают и полностью независимы), и отдельно сборка с заказами, где происходит весь workflow, последняя сборка пользуется предыдущими двумя.
Такое деление помогает себя контролировать и избегать лишних связей между компонентами.

AL>Ну, в своем видении системы, я бы сделал это свойством определенно в одном классе Order, в этом случае, не приходилось бы думать содержит оно внутри логику для работы с БД или нет и где оно в OrderManager или в OrderInfo

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

AL>Очень интересует, как можно метод сделать виртуальным (тот же Register)? Можно на примере кода, с которого я начинал тему.


public static class PersonManager
{
        public static void Register(ProfessorPerson person)
        {
                IDAL.Save(person); 
                
                // Логика специфичная для профессора
                // ....
                
        }
        
        public static void Register(StudentPerson person)
        {
                IDAL.Save(person);
                
                // Логика специфичная для студента
                // ....
        }
}


Или я не очень понимаю, чего ты хочешь добиться....

AL>Не могу понять, почему бизнес логику и бизнес сущность нужно разделять? Для чего и в чем это помогает?

Это помогает переиспользовать и бизнес логику, и сущности, и легко менять одно независимо от другого.
Можно покрутить их по отдельности, что-то переделать и приставить обратно, при этом есть уверенность, что нигде ничего не сломается. Есть такой термин "уменьшение связности", вот это вот оно.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re: Bussiness Entity, Component and DAL
От: Lloyd Россия  
Дата: 28.02.07 09:15
Оценка:
Здравствуйте, alastochkin, Вы писали:

A>Я использую custom entities (т.е. не DataSet'ы, а свои классы, см. пример кода ниже). Если я выделяю DAL в отдельную сборку, я не могу поместить ссылку на BLL, т.к. circular reference. Поэтому для того, чтобы я мог получить доступ из DAL к объектам бизнес логики мне нужно еще создать IPerson (куда вытащить все property Person, которые используются из DAL) и сделать Factory для Person, чтобы в DAL можно было создавать экземпляр Person.


A>Поэтому получается, для одного класса Person, мне нужно сделать как минимум 4 класса: BLL.Person, IDAL.Person, Model.IPerson, DAL.Person. Что получается слишком громоздко. И тем более, если в BLL.Person я получаю список, мне нужно будет каждый IPerson кастить в Person, что не совсем удобно.


Просто вынеси Entity-классы в отдельную сборку и все будет хорошо.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 28.02.07 10:09
Оценка:
IB>В принципе нормально. Но я в своих проектах обычно делю на сборки "вертикально", по компонентам. Например, отдельная сборка — работа с пользователями, включая DAL, BLL и BizEntity, отдельная сборка — продукты и их иерархия (эти две сборки ничего друг о друге не знают и полностью независимы), и отдельно сборка с заказами, где происходит весь workflow, последняя сборка пользуется предыдущими двумя.
IB>Такое деление помогает себя контролировать и избегать лишних связей между компонентами.
Да, полностью согласен. У нас дополнительно к такому делению "вертикаль" разбита еще на сборки DAL и BLL, а отсюда рождается гемор.
Наверное, следует объединить, как ты предлагаешь.

AL>>Ну, в своем видении системы, я бы сделал это свойством определенно в одном классе Order, в этом случае, не приходилось бы думать содержит оно внутри логику для работы с БД или нет и где оно в OrderManager или в OrderInfo

IB>И Order оказался бы гвоздями прибитым к DAL, больше ты его нигде использовать не сможешь. Более того, при изменении контракта с DAL, тебе придется перетряхивать весь проект, на предмет — не сломалось ли что, поскольку ты не знаешь где именно были обращения к DAL.
Обращение к DAL.Order могут быть только из BLL.Order, больше нигде. По идее DAL.Order должен быть protected class и содержатся в BLL.Order, чтобы другие объекты не могли получить к нему доступ.
Можешь привести пример, где нужен не прибитый гвоздями объект Order. Просто я пока с этим не сталкивался, но учитывать нужно.

AL>>Очень интересует, как можно метод сделать виртуальным (тот же Register)? Можно на примере кода, с которого я начинал тему.

IB>
IB>public static class PersonManager
IB>{
IB>        public static void Register(ProfessorPerson person)
IB>        {
IB>                IDAL.Save(person); 
IB>                // Логика специфичная для профессора
IB>                // ....
IB>        }
        
IB>        public static void Register(StudentPerson person)
IB>        {
IB>                IDAL.Save(person);
IB>                // Логика специфичная для студента
IB>                // ....
IB>        }
IB>}
IB>

IB>Или я не очень понимаю, чего ты хочешь добиться....
Вот у тебя тут получилось, что структура вышла плоская. Т.е. не смотря на то, что объекты разные, все лежит в одном классе на одном уровне. Теоретически, я не могу создать новый класс BabyPerson без перекомпиляции всей этой статической бизнес логики. И если бы лэто огически был наследник от, скажем, ProfessorPerson — тогда пришлось бы вызывать родительский метод вручную, хотя в C# уже есть на это дело инструменты ООП — virtual и override.

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

Person person = PersonManager.GetById(id)
PersonManager.Register(person)


В моем случае это выглядело бы так
Person person = PersonManager.GetById(id)
person.Register()


AL>>Не могу понять, почему бизнес логику и бизнес сущность нужно разделять? Для чего и в чем это помогает?

IB>Это помогает переиспользовать и бизнес логику, и сущности, и легко менять одно независимо от другого.
IB>Можно покрутить их по отдельности, что-то переделать и приставить обратно, при этом есть уверенность, что нигде ничего не сломается. Есть такой термин "уменьшение связности", вот это вот оно.
Примерно подсознательно представляю о чем ты говоришь, но формализовать не могу. Можешь привести пример какой-нибудь?
И чем ООП подход в этом случае не устроит.
Re[2]: Bussiness Entity, Component and DAL
От: Andrey Lastochkin Россия  
Дата: 28.02.07 10:12
Оценка:
A>>Поэтому получается, для одного класса Person, мне нужно сделать как минимум 4 класса: BLL.Person, IDAL.Person, Model.IPerson, DAL.Person. Что получается слишком громоздко. И тем более, если в BLL.Person я получаю список, мне нужно будет каждый IPerson кастить в Person, что не совсем удобно.
L>Просто вынеси Entity-классы в отдельную сборку и все будет хорошо.
А как же наследование, дружище?
Re[2]: Bussiness Entity, Component and DAL
От: IB Австрия http://rsdn.ru
Дата: 28.02.07 10:21
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Просто вынеси Entity-классы в отдельную сборку и все будет хорошо.

Не будет, он же хочет из Entity пользоваться DAL.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[4]: Bussiness Entity, Component and DAL
От: _FRED_ Черногория
Дата: 28.02.07 10:35
Оценка:
Здравствуйте, IT, Вы писали:

IT>На практике получается, что бизнес-логика по-любому размазывается по всему приложению, по-этому бороться с этим не нужно. Нужно это возглавить и организовать.


Help will always be given at Hogwarts to those who ask for it.
Re[5]: Bussiness Entity, Component and DAL
От: Trean Беларусь http://axamit.com/
Дата: 28.02.07 10:57
Оценка:
Здравствуйте, Andrey Lastochkin, Вы писали:

T>>А почему бы не подсмотреть как это сделано в ORM средствах ((N)Hibernate, JDO)? Там люди уже продумали многие тонкие моменты.

T>>Если нельзя использовать ORM, то лично я выбираю DAO + POJO (Data Objects).
T>>DAO состоит из интерфейса и реализации методов доступа к DB
AL>Как я понял это IDAL, о котором я говорил выше?

T>> и POJO класс+интерфейс

AL>Т.е. тот же BLL.Person и Model.IPerson?

T>> если мне нужно гарантировать, что класс не будет изменяться за пределами того места где он инициализируется (т.е. только accessors методы в интерфейсе). От приведения типа не спасет конечно, но его как раз можно отследить средствами IDE. Можно и без интерфейса обойтись.

AL>А, фабрику как делаешь в этом случае? Для каждого класса в конфиге прописываешь, или может быть пишешь некий алгоритм формирования имя типа и придерживаешься жесткого правила именования.

AL>PS: я использую BLToolkit, но от DALа полностью не уйти, т.к. из хранимок возвращаются порой сложные структуры, которые без дополнительного маппинга не вернешь.

AL>Еще, специально для интерфейсных нужд я выделяю часть DALUI который находится в DAL и вызывается напрямую из UI. Например, для получения постраничных выборок, сортировок, подсчета количества документов, возвращение малого количества полей из связанных сущностей, вместо создания множества непроинициализированных объектов.
AL>Это либо конкретные UIEntity (стараюсь чтобы их было как можно меньше), либо DataTable/DataSet.

http://en.wikipedia.org/wiki/Data_Transfer_Object
http://en.wikipedia.org/wiki/Data_Access_Object
http://java.sun.com/blueprints/patterns/DAO.html
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

DAO паттерн вообще platform-agnostic. Недостаток — достаточно много кода. Но если использовать средства автогенерации и динамические прокси для интерфейсов, то можно существенно себе облегчить жизнь. Где-то так.
Re[3]: Bussiness Entity, Component and DAL
От: Lloyd Россия  
Дата: 28.02.07 11:20
Оценка:
Здравствуйте, Andrey Lastochkin, Вы писали:

L>>Просто вынеси Entity-классы в отдельную сборку и все будет хорошо.

AL>А как же наследование, дружище?

А как это может помещать?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Bussiness Entity, Component and DAL
От: Lloyd Россия  
Дата: 28.02.07 11:20
Оценка:
Здравствуйте, IB, Вы писали:

L>>Просто вынеси Entity-классы в отдельную сборку и все будет хорошо.

IB>Не будет, он же хочет из Entity пользоваться DAL.
Тады ой.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Bussiness Entity, Component and DAL
От: снежок Россия  
Дата: 28.02.07 12:49
Оценка: 4 (1)
А баба яга против ...
IB>1. Не выносят DAL в отдельную сборку. Сборка — это единица развертывания, а на практике развертывать DAL отдельно от BLL приходится редко. (Специально для педантов и зануд замечу, что это вовсе не означает отказ от разделения на DAL и BLL ).
Выносят, выносят..., и обычно это связано с нежеланием и не примиримостью архитектора развертывать код с обращением к БД на стороне клиента. Мотивируется обычно это соображениями безопасности, типа "нечего клиенту знать об объектах БД".

Теперь о решении проблемы circular reference как таковой:

1.Это создание прокси-классов, реализующих общий Facade-интерфейс.
Так существует ProxyDAL, ProxyService.
У меня примерно так: Клиент обращается к Agents, которые в зависимости от контекста выполнения приложения (клиент/сервер), инстанцируют тот или иной Singleton-Proxy (ProxyDAL, ProxyService). Какой прокси инстанцировать, задается в конфиге комбинацией IRemoteFacade+ProxyAssemblity+ProxyClass.
Proxy в свою очередь, уже напрямую, обращаются к DAL или к сервисам.
Может с небольшими кусочками примеров, чуть более ясно будет:
namespace BF.Core
{
   [ServiceContract]
    public interface ICoreFacade
    {
        [OperationContract]
        void Test(System.String ticketSID);
        [OperationContract]
        void Create_SysObject(SessionContext context, SysObject obj);
    }
}


namespace BF.Core
{
    public class BaseAgent<T>
    {
        private static T m_Proxy;
        public static T Proxy
        {
            get
            {
                if (m_Proxy == null)
                {
                    m_Proxy = (T)BF.Loader.LoadProxy(System.String.Format("Proxy:{0}.{1}",typeof(T).Namespace, typeof(T).Name));
                                        //Loader просто через рефлекшин инстанцирует объект по переданным параметрам, основной кусок кода:
                                            //asm             = System.Reflection.Assembly.Load(assemblityName);
                                            //result          = asm.CreateInstance(className);
               }
                return m_Proxy;
            }
        }
    }
}



namespace BF.Core
{
    public class CoreAgent:BaseAgent<ICoreFacade>
    {
        public static void Test() {
            Proxy.Test(SessionContext context);
        }
        public static void Create_SysObject(SessionContext context, SysObject obj) {
            Proxy.Create_SysObject(context, obj);
        }
    }
}

namespace BF.Core
{
    public class ProxyDAL:ICoreFacade
    {
        public void Test(SessionContext context)
        {
            BF.Core.DAL.SysObject.Test(context);
        }

        public void Create_SysObject(SessionContext context, SysObject obj)
        {
            BF.Core.DAL.SysObject.Create(context, obj);
        }
        }
}

На самом деле решается еще одна проблема: допустим какое-либо приложение не требует таких глубоких и масштабируемых решений на сервисах и т.д
Тогда приложение просто переконфигурируется на интанцирование DALProxy и никаких сервисов разворачивать не нужно. "Клиент" работает напрямую с DAL. Характерно когда есть некоторый общий фреймворк, используемый в разных типах приложений. Тут как раз легко "прортировать" его, например, для простейшего веб-приложения.
Еще пример полезности прокси-классов — DAL для разных СУБД или даже для xml-storage.

Подобный же подход используется в знакомой, наверное, многим CSLA.NET (C# Bussiness Objects) (см. DataPortal-классы)
Думаю, обсуждение этой библиотеки выходит за рамки топика, однако идей там предостаточно как хороших, так и весьма спорных и плохих.
Кстати DAL от BO там не отделен, ни в классах, ни в сборках, что я считаю весьма плохим.

2. Еще вариант по сабжу, да простит меня IT, и другие нелюбители DTO , но тут то он как раз ПОПУТНО решает данную проблему, т.е. BO мапится на DTO, с которым в свою очередь и работает DAL. Но подчеркиваю (во избежании флеймогона), что это всего лишь попутная задача решаемая DTO.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Bussiness Entity, Component and DAL
От: снежок Россия  
Дата: 28.02.07 12:56
Оценка:
L>Тады ой.
Тады Proxy и динамический лоадинг: Re[2]: Bussiness Entity, Component and DAL
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.