Как правильно реализовать Domain Model?
От: seas  
Дата: 16.10.07 21:39
Оценка:
hi!

Проектирую корпоративные приложения на связке Java + Hibernate + Spring + DWR + Dojo.
Первым делом берусь за Domain Model — POJO + SQL Scheme + Hibernate Mapping.
Цели которым задаюсь:
1. дать достаточную функциональную гибкость этой модели,
2. исключить мешающую мне излишнюю гибкость и возможные ошибки на этапе занесения данных в базу.
3. обеспечить расширяемость и изменяемость системы под новые требования, если они остаются в рамках общей концепции приложения.

В результате получаю package из POJO, который:
1. Содержит несколько деревьев наслодования, которые практически повторяют друг друга в названиях и структуре наследования (но не в данных и время жизни объектов в них разное),
2. Классы в разных деревьях имеют связи между собой, причем связи не между базовыми классами, а между потомками.

Соответственно, ради достижения Цели 2, мы жертвуем объектно-ориентированностью, ведь классы связаны не через интерфейсы (коими являются базовые классы), а на нижнем уровне (Результат 2) — но там связи строго типизированные и база данных получается соответствующая (использую режим Hibernate — Table per Class). Т.е. за нас сначала проверяет компилятор не напортачили-ли мы где-нибудь и не положим-ли шлак в базу, а потом проверит Hibernate когда мы ему подсунем шлак чтобы положить в базу. Система получает достаточно расширяемая за счет добавления новых подклассов уже существующих базовых классов, полиморфная логика зачастую реализуется снаружи, а не внутри классов данных — во вспомогательных Visitorах.

Но так или иначе, мы жертвуем ООП и меня в это ткнули носом. Но я считаю Domain Model — моделью данных, а не логики — ведь все-же она состоит из POJO.

Так вот прав-ли я? Действитель-но ли можно считать такой не объектно ориентированный дизайн — вполне приемлемым для модели данных? Что можно почитать из теории по этому поводу?
Re: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 17.10.07 06:21
Оценка: +1
Здравствуйте, seas, Вы писали:

S>В результате получаю package из POJO, который:

S>1. Содержит несколько деревьев наслодования, которые практически повторяют друг друга в названиях и структуре наследования (но не в данных и время жизни объектов в них разное),
Явный признак того, что в архитектуре заложена серьезная ошибка.

S>2. Классы в разных деревьях имеют связи между собой, причем связи не между базовыми классами, а между потомками.

Приведите, пожалуйста, примеры таких классов.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[2]: Как правильно реализовать Domain Model?
От: seas  
Дата: 17.10.07 07:00
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, seas, Вы писали:


S>>В результате получаю package из POJO, который:

S>>1. Содержит несколько деревьев наслодования, которые практически повторяют друг друга в названиях и структуре наследования (но не в данных и время жизни объектов в них разное),
КЛ>Явный признак того, что в архитектуре заложена серьезная ошибка.
Опять-же обращаю внимание, что я разрабатываю в конечном итоге модель данных, а не логики, хотя модель данных и выражена в терминах классов и для общности группируется в деревья наследования. На самом деле это преимущественно POJO без полиморфной логики и хранятся в базе данных с помощью Hibernate.

S>>2. Классы в разных деревьях имеют связи между собой, причем связи не между базовыми классами, а между потомками.

КЛ>Приведите, пожалуйста, примеры таких классов.
Первое дерево, с самыми долгоживущими объектами (буквально задаются до старта системы):
1. abstract class Role;
2. class RolePersonal extends Role;
3. class RoleOverGroup extends Role;

Второе дерево (объекты создаются во время работы, но не слишком часто, могут удаляться):
1. abstract class Assignment { private User user; }
2. class AssignmentPersonal extends Assignment { private RolePersonal rolePersonal;}
3. class AssignmentOverGroup extends Assignment { private Group group; private RoleOverGroup roleOverGroup; }

Третье дерево (объекты создаются динамически и очень часто, не удаляются, хранятся в качестве истории):
1. abstract class ApprovalPath { private Document document; }
2. class ApprovalPathPerson { private User dueApprover; }
3. class ApprovalPathOverGroup { private Group group; private RoleOverGroup roleOverGroup; }

таким образом мы имеем три параллельно идущих дерева, как тока добавляем подкласс в дерево Role, придется расширять все остальные.
но за счет типизации связей между подклассами (ApprovalpathOverGroup -> RoleOverGroup, AssignmentPersonal -> RolePersonal) компилятор заругает нас за ошибки и Hibernate потом не даст положить туфту в базу.
Re[3]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 17.10.07 07:50
Оценка:
Здравствуйте, seas, Вы писали:

S>Здравствуйте, Кирилл Лебедев, Вы писали:


КЛ>>Здравствуйте, seas, Вы писали:


S>Первое дерево, с самыми долгоживущими объектами (буквально задаются до старта системы):

S>1. abstract class Role;
S>2. class RolePersonal extends Role;
S>3. class RoleOverGroup extends Role;

S>Второе дерево (объекты создаются во время работы, но не слишком часто, могут удаляться):

S>1. abstract class Assignment { private User user; }
S>2. class AssignmentPersonal extends Assignment { private RolePersonal rolePersonal;}
S>3. class AssignmentOverGroup extends Assignment { private Group group; private RoleOverGroup roleOverGroup; }

S>Третье дерево (объекты создаются динамически и очень часто, не удаляются, хранятся в качестве истории):

S>1. abstract class ApprovalPath { private Document document; }
S>2. class ApprovalPathPerson { private User dueApprover; }
S>3. class ApprovalPathOverGroup { private Group group; private RoleOverGroup roleOverGroup; }

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

может как-то выделить разделение на Personal и OverGroup в отдельную иерарахию и сделать ссылки на ее объект ,если у например ApprovalPathPerson и ApprovalPathOverGroup одинаковые интерфейсы.,. если бы видеть весь код и его назначение...
Re[4]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 17.10.07 09:28
Оценка:
Здравствуйте, kejroot, Вы писали:

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

Значит плохую книжку читал.
Re[5]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 17.10.07 09:43
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, kejroot, Вы писали:


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

GZ>Значит плохую книжку читал.
вам лучше знать "Рефакторинг с использованием шаблонов", правда базовый класс был фабрикой для потомков..
Re[6]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 17.10.07 14:39
Оценка:
Здравствуйте, kejroot, Вы писали:

K>Здравствуйте, GlebZ, Вы писали:


GZ>>Здравствуйте, kejroot, Вы писали:


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

GZ>>Значит плохую книжку читал.
K>вам лучше знать "Рефакторинг с использованием шаблонов", правда базовый класс был фабрикой для потомков..
То есть, он был полиморфным, или же знал о поведении своих потомков?
Re[7]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 17.10.07 14:54
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, kejroot, Вы писали:


K>>Здравствуйте, GlebZ, Вы писали:


GZ>>>Здравствуйте, kejroot, Вы писали:


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

GZ>>>Значит плохую книжку читал.
K>>вам лучше знать "Рефакторинг с использованием шаблонов", правда базовый класс был фабрикой для потомков..
GZ>То есть, он был полиморфным, или же знал о поведении своих потомков?
в примере у AttributeDescriptor создавались методы forBoolean, forClass, forInteger, возвращавщие разные типы потомков BooleanDescriptor, DefaultDescriptor, ReferenceDescriptor. то есть он знал о существовании своих потомков — вызывал конструктор. Факт!
Re[8]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 17.10.07 15:08
Оценка:
Здравствуйте, kejroot, Вы писали:

K>в примере у AttributeDescriptor создавались методы forBoolean, forClass, forInteger, возвращавщие разные типы потомков BooleanDescriptor, DefaultDescriptor, ReferenceDescriptor. то есть он знал о существовании своих потомков — вызывал конструктор. Факт!

То есть, это фактически набор некоторых функций которые генерили новые инстансы классов, но ни в коем случае не лезли в поведение своего инстанса кроме как через полиморфные вызовы?
Re[9]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 17.10.07 15:22
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, kejroot, Вы писали:


K>>в примере у AttributeDescriptor создавались методы forBoolean, forClass, forInteger, возвращавщие разные типы потомков BooleanDescriptor, DefaultDescriptor, ReferenceDescriptor. то есть он знал о существовании своих потомков — вызывал конструктор. Факт!

GZ>То есть, это фактически набор некоторых функций которые генерили новые инстансы классов, но ни в коем случае не лезли в поведение своего инстанса кроме как через полиморфные вызовы?
да! фабрика..
а базовый класс был абстрактным и эти функции возвращали базовый же тип. полиморфные вызовы, это, если я правильно понял, даже щитай и не лезли, это ж стандартные средства языка! в базовом эти методы были абстрактные
Re[3]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 17.10.07 15:54
Оценка:
Здравствуйте, seas, Вы писали:

S>Опять-же обращаю внимание, что я разрабатываю в конечном итоге модель данных, а не логики, хотя модель данных и выражена в терминах классов и для общности группируется в деревья наследования. На самом деле это преимущественно POJO без полиморфной логики и хранятся в базе данных с помощью Hibernate.

Все таки на логику поведение посмотреть всегда стоит. Посмотрите на прецеденты использования. Есть у меня смутное подозрение что при использовании единая таблица ролей, или Approval будет эффективней. Эффективность БД очень важная вещь а рефакторить ее сложнее чем остальную логику(поскольку за этим может потянуться большой хвост в изменениях в бизнес-логике). Поэтому желательно предполагать какие будут транзакции.
Re[10]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 17.10.07 16:18
Оценка:
Здравствуйте, kejroot, Вы писали:

K>да! фабрика..

K>а базовый класс был абстрактным и эти функции возвращали базовый же тип. полиморфные вызовы, это, если я правильно понял, даже щитай и не лезли, это ж стандартные средства языка! в базовом эти методы были абстрактные
Вопрос не в стандартных средствах языка. Вредны цикличные зависимости поведения. От них всегда неприятности. В случае наследования, наследуемый класс предоставляет некоторый интерфейс поведения который должен быть реализован/дополнен его наследниками. Как только наследуемый класс начинает понимать поведение наследника, мы получаем бардак в виде того, что все наследники должны определять данное поведение. Что немедленно приводит к сипуке в случае расширение модели.

зы. Параллельные иерархии не так уж плохо, но и не так уж хорошо. Хороший пример паттерн Visitor(обсуждался в форуме неоднократно). Главное чтобы был смысл в реализации оного.
Re[11]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 18.10.07 04:45
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, kejroot, Вы писали:


K>>да! фабрика..

K>>а базовый класс был абстрактным и эти функции возвращали базовый же тип. полиморфные вызовы, это, если я правильно понял, даже щитай и не лезли, это ж стандартные средства языка! в базовом эти методы были абстрактные
GZ>Вопрос не в стандартных средствах языка. Вредны цикличные зависимости поведения. От них всегда неприятности.
Это я все понимаю. и с этим не спорю (см. ниже *). я не говорю, что всегда можно создавать такие зависимости, как было описано. из-за них при добавлении наслединика, нужно расширять интерфейс или менять реализацию методов наследуемого.
но всё же это связь из паттерна фабрика, в нее тоже добавляются сведения о новых видах классов.

GZ>В случае наследования, наследуемый класс предоставляет некоторый интерфейс поведения который должен быть реализован/дополнен его наследниками. Как только наследуемый класс начинает понимать поведение наследника, ...

Что вы понимаете под "наследуемый класс понимает поведение наследника"? Знает сигнатуру методов, которые наследник доопределил? Это, согласен, плохо. Правда, если он использует конкретного наследника, он знает его тип и к другим наследникам это знание сигнатры доопределённых методов не относится. * Но всё равно вреден факт знания о наследнике, т.к. нарушается порядок в иерархии.
В примере это сделано для компактности и простоты, чтобы совместить в одном классе конкретную фабрику и абстрактный продукт. Я думаю это оправдано, если учесть, что сокращается количество классов, о которых нужно знать клиенту. Кроме того при необходимости всегда можно сделать Extract Class, ибо код не забетонирован!)

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

почему вы называете бардаком стандартный механизм абстрактных методов? примеры использования — Template Method, Factory Method. его можно не использовать, если уж есть наследники, которым эти методы не нужны, можно же взять виртуальные методы наконец

GZ>зы. Параллельные иерархии не так уж плохо, но и не так уж хорошо. Хороший пример паттерн Visitor(обсуждался в форуме неоднократно). Главное чтобы был смысл в реализации оного.

Вцелом согласен, только Visitor это не очень хороший пример параллельной иерархии. больше подходит Iterator. хороший пример факта "допустимости" параллельной иерархии, правда не понятно как он поможет в решении проблемы автора топика.. а Визитор похож на Builder, там для каждого подкласса сделан метод, и иерархия для разных целей вИзита или билда.
Re[3]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 18.10.07 10:27
Оценка:
Здравствуйте, seas, Вы писали:

S>Опять-же обращаю внимание, что я разрабатываю в конечном итоге модель данных, а не логики, хотя модель данных и выражена в терминах классов и для общности группируется в деревья наследования. На самом деле это преимущественно POJO без полиморфной логики и хранятся в базе данных с помощью Hibernate.

Понимаю, но, на мой взгляд, в этом и заключается причина ошибки. Разработать модель данных в отрыве от логики работы программы может и можно, но бесперспективно, т.к. такая модель будет неуклюжа, громоздка и неудобна в использовании. Любая структура — в том числе и структура данных! — разрабатывается под решаемые задачи. Если Вам нужен последовательный доступ к элементам коллекции и неограниченная возможность по добавлению элементов, Вы предпочтете список. Если Вам требуется произвольный доступ (по индексу), Вы предпочтете массив. Какую структуру (модель) данных выбрать — зависит от задач.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[3]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 18.10.07 11:13
Оценка:
Здравствуйте, seas, Вы писали:

S>Первое дерево, с самыми долгоживущими объектами (буквально задаются до старта системы):

А какие обязанности у Ваших классов? За что отвечает группа классов Role? За что отвечают группы Assignment и Approval?

S>1. abstract class Role;

S>2. class RolePersonal extends Role;
S>3. class RoleOverGroup extends Role;
Есть предложения реорганизовать Вашу иерархию таким образом:

class Role {...};
class PersonalRole : public Role {...};
class GroupRole : public Role {...};

class Assignment
{
   User * m_pUser;
   Group * m_pGroup;
   Role * n_pRole;
};

class Approval
{
   Document * m_pDocument;
   Role * m_pRole;
   Group * m_pGroup;
};
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[12]: Как правильно реализовать Domain Model?
От: Larvef Германия  
Дата: 18.10.07 12:04
Оценка:
Здравствуйте, kejroot, Вы писали:

K>Что вы понимаете под "наследуемый класс понимает поведение наследника"? Знает сигнатуру методов, которые наследник доопределил? Это, согласен, плохо.


Прошу прощения, что встреваю в дискуссию. Я правильно понимаю, что исходя из вышесказанного использование абстрактных методов — плохо в архитектурном смысле?
Re[13]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 18.10.07 12:43
Оценка:
Здравствуйте, Larvef, Вы писали:

L>Здравствуйте, kejroot, Вы писали:


K>>Что вы понимаете под "наследуемый класс понимает поведение наследника"? Знает сигнатуру методов, которые наследник доопределил? Это, согласен, плохо.


L>Прошу прощения, что встреваю в дискуссию. Я правильно понимаю, что исходя из вышесказанного использование абстрактных методов — плохо в архитектурном смысле?


я именно, пишу что не плохо, когда оправдано — хорошо.
вот так я имел ввиду плохо:

class Node {
    private ParentNode parentField;
    public Operation() {
        parentField.AddChild(...);
    }
}

class ParentNode extends Node {
    private List<Node> children;
    ...
    public void AddChild(Node arg) {
        children.Add(arg);
    }
    ...
}

если бы AddChild был абстрактный метод, поле parentField можно было бы сделать типом Node и тогда всё нормально
Re[12]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 18.10.07 17:03
Оценка:
Здравствуйте, kejroot, Вы писали:

GZ>>В случае наследования, наследуемый класс предоставляет некоторый интерфейс поведения который должен быть реализован/дополнен его наследниками. Как только наследуемый класс начинает понимать поведение наследника, ...

K>Что вы понимаете под "наследуемый класс понимает поведение наследника"? Знает сигнатуру методов, которые наследник доопределил? Это, согласен, плохо. Правда, если он использует конкретного наследника, он знает его тип и к другим наследникам это знание сигнатры доопределённых методов не относится. * Но всё равно вреден факт знания о наследнике, т.к. нарушается порядок в иерархии.
Плохо если типа
void Method()
{
    if (this is Obj1)
       ((Obj1).Method2();
    else
       ((Obj2).Method3();
}

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

K>В примере это сделано для компактности и простоты, чтобы совместить в одном классе конкретную фабрику и абстрактный продукт. Я думаю это оправдано, если учесть, что сокращается количество классов, о которых нужно знать клиенту. Кроме того при необходимости всегда можно сделать Extract Class, ибо код не забетонирован!)

+1 Смысловая часть в самом паттерне хорошо прописана. (в вашей книге не знаю, но в Гамма это все прекрасно описано)

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

K>почему вы называете бардаком стандартный механизм абстрактных методов? примеры использования — Template Method, Factory Method. его можно не использовать, если уж есть наследники, которым эти методы не нужны, можно же взять виртуальные методы наконец
Я не говорил об абстактных методах. Я говорил о поведении наследников. Наследники знают о поведении своего базового. Они могут это выявить через контракт. Базовый же не должен привязываться к наследникам сверх интерфейса который он предоставляет.

K>Вцелом согласен, только Visitor это не очень хороший пример параллельной иерархии. больше подходит Iterator. хороший пример факта "допустимости" параллельной иерархии, правда не понятно как он поможет в решении проблемы автора топика.. а Визитор похож на Builder, там для каждого подкласса сделан метод, и иерархия для разных целей вИзита или билда.

У автора топика не проблема ООП. Это проблема модели данных. Там другие законы.
Re[13]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 04:25
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Плохо если типа

GZ>
GZ>void Method()
GZ>{
GZ>    if (this is Obj1)
GZ>       ((Obj1).Method2();
GZ>    else
GZ>       ((Obj2).Method3();
GZ>}
GZ>

GZ>Если добавляется новый наследник, то мы получаем проблемы неявного поведения.
даа, плохо.. только опять недопёр, что значит неявное поведение?..
правда что может заставить писать так, если можно написать так:

class Obj
{
    virtual void Method()
    { 
    }
}

class Obj1 : Obj
{
    override void Method()
    { 
        // тело Method2
    }
}

class Obj2 : Obj
{
    override void Method()
    { 
        // тело Method3
    }
}

.. или там чтото ещё?..

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

K>>почему вы называете бардаком стандартный механизм абстрактных методов? примеры использования — Template Method, Factory Method. его можно не использовать, если уж есть наследники, которым эти методы не нужны, можно же взять виртуальные методы наконец
GZ>Я не говорил об абстактных методах. Я говорил о поведении наследников. Наследники знают о поведении своего базового. Они могут это выявить через контракт. Базовый же не должен привязываться к наследникам сверх интерфейса который он предоставляет.
просто я так понял, что если сказано "наследники должны определять данное поведение", то эта обязанность закреплена контрактом(абстрактным методом)..

GZ>У автора топика не проблема ООП. Это проблема модели данных. Там другие законы.

Тогда, с точки зрения этих законов, его решение признается нормальным, а те кто его "ткнули носом" — несведующими. или нет? а какие тогда проблемы в этом решении?
1. параллельные иерархии, здесь канают. или нет?
2. узко типизированные связи между потомками тоже. я кстати, вообще не понимаю, почему seas считает это не кошерным?
может есть ещё неохваченные аспекты?
Re[4]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 04:37
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Есть предложения реорганизовать Вашу иерархию таким образом:


КЛ>
КЛ>class Role {...};
КЛ>class PersonalRole : public Role {...};
КЛ>class GroupRole : public Role {...};

КЛ>class Assignment
КЛ>{
КЛ>   User * m_pUser;
КЛ>   Group * m_pGroup;
КЛ>   Role * n_pRole;
КЛ>};

КЛ>class Approval
КЛ>{
КЛ>   Document * m_pDocument;
КЛ>   Role * m_pRole;
КЛ>   Group * m_pGroup;
КЛ>};
КЛ>


на мой взгляд, это могло бы нарушить Single Responsibility Principle, что обычно приводит к смешению ответственности и разрастанию классов (засчёт поведения).. ну ладно, раз это модель данных, то не важно. но другая проблема! — ослабляется автоматическая проверка типов компилятором и Hibernate'ом! Мы же боимся закона Мэрфи!
Re[5]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 19.10.07 05:11
Оценка:
Здравствуйте, kejroot, Вы писали:

K>на мой взгляд, это могло бы нарушить Single Responsibility Principle, что обычно приводит к смешению ответственности и разрастанию классов (засчёт поведения)..

Отнюдь. Наоборот, это предыдущий вариант нарушал Single Responsibility Principle, т.к. различия между сущностями были разнесены по трем иерархиям: что-то отнесено к одной, что-то — к другой, а что-то — к третьей. В предложенном же мною варианте все различия помещены в одну иерархию классов Role.

K>ну ладно, раз это модель данных, то не важно. но другая проблема! — ослабляется автоматическая проверка типов компилятором и Hibernate'ом! Мы же боимся закона Мэрфи!

В чем Вы видите такое ослабление?
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[6]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 06:29
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, kejroot, Вы писали:


K>>на мой взгляд, это могло бы нарушить Single Responsibility Principle, что обычно приводит к смешению ответственности и разрастанию классов (засчёт поведения)..

КЛ>Отнюдь. Наоборот, это предыдущий вариант нарушал Single Responsibility Principle, т.к. различия между сущностями были разнесены по трем иерархиям: что-то отнесено к одной, что-то — к другой, а что-то — к третьей. В предложенном же мною варианте все различия помещены в одну иерархию классов Role.
а прошу прощения! плохо посмотрел. что-то похожее я и сам предлагал.
правда не совсем понятно какие изменения между первоначальным:
1. abstract class Role;
2. class RolePersonal extends Role;
3. class RoleOverGroup extends Role;
и
class Role {...};
class PersonalRole : public Role {...};
class GroupRole : public Role {...};


K>>ну ладно, раз это модель данных, то не важно. но другая проблема! — ослабляется автоматическая проверка типов компилятором и Hibernate'ом! Мы же боимся закона Мэрфи!

КЛ>В чем Вы видите такое ослабление?
Но оно есть! поле m_pGroup должно быть заполнено или нет в зависимости от "различия между сущностями". предлагаю перенести его в класс GroupRole.
в Approval нужен еще User dueApprover, который так же зависит от вида сущности. куда его приткнуть?
кроме того, seas изначально сказал, что использует не базовый тип поля для контроля. — знание, что Role — это PersonalRole, у которого видимо свой набор полей, ещё дорогово стоит!
Re[7]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 19.10.07 08:32
Оценка:
Здравствуйте, kejroot, Вы писали:

K>правда не совсем понятно какие изменения между первоначальным:

Никаких — просто поменял названия на, как мне кажется, более уместные.

K>Но оно есть! поле m_pGroup должно быть заполнено или нет в зависимости от "различия между сущностями". предлагаю перенести его в класс GroupRole.

Можно ввести понятие фиктивной группы или же вообще отказаться от явного декларирования различий между Person и Group. Если есть Role, то и должен быть Actor, который играет эту роль. А уж что это за actor — person или group — дело десятое.

K>в Approval нужен еще User dueApprover, который так же зависит от вида сущности. куда его приткнуть?

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

K>кроме того, seas изначально сказал, что использует не базовый тип поля для контроля. — знание, что Role — это PersonalRole, у которого видимо свой набор полей, ещё дорогово стоит!

В том-то и различие в подходах. Если классы Role, PersonalRole и GroupRole выступают просто в виде наборов полей, то группировать можно, как угодно. Потому что группируй — не группируй, а все равно получишь... неудобное решение. Если же считать, что все роли обладают одинаковыми обязанностями (просто реализации этих обязанностей у них разные), то совершенно неважно знать, какая это роль — PersonalRole или GroupRole.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[14]: Как правильно реализовать Domain Model?
От: GlebZ Россия  
Дата: 19.10.07 08:40
Оценка:
Здравствуйте, kejroot, Вы писали:


GZ>>Плохо если типа

GZ>>
GZ>>void Method()
GZ>>{
GZ>>    if (this is Obj1)
GZ>>       ((Obj1).Method2();
GZ>>    else
GZ>>       ((Obj2).Method3();
GZ>>}
GZ>>

GZ>>Если добавляется новый наследник, то мы получаем проблемы неявного поведения.
K>даа, плохо.. только опять недопёр, что значит неявное поведение?..
Это значит что если появился наследник Obj3 — то этот метод будет давать ошибку, смысл которой можно получить только через трассировку.

K>правда что может заставить писать так, если можно написать так:

K>
K>class Obj
K>{
K>    virtual void Method()
K>    { 
K>    }
K>}

K>class Obj1 : Obj
K>{
K>    override void Method()
K>    { 
K>        // тело Method2
K>    }
K>}

K>class Obj2 : Obj
K>{
K>    override void Method()
K>    { 
K>        // тело Method3
K>    }
K>}
K>

K>.. или там чтото ещё?..
Правильно. Ты выделил это в контракт базового класса. Поэтому мы решили одну проблему.(путем изменения базового и перетестированием всех наследников и их зависимостей). Но с одним условием, если у нас в Method идет одинарный вызов наследника. А если это последовательность вызовов методов как базового класса так и наследников? А если у нас появляется новый наследник у которого часть поведения эквивалентна Obj1 а другая часть эквивалентна Obj2?

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

K>>>почему вы называете бардаком стандартный механизм абстрактных методов? примеры использования — Template Method, Factory Method. его можно не использовать, если уж есть наследники, которым эти методы не нужны, можно же взять виртуальные методы наконец
GZ>>Я не говорил об абстактных методах. Я говорил о поведении наследников. Наследники знают о поведении своего базового. Они могут это выявить через контракт. Базовый же не должен привязываться к наследникам сверх интерфейса который он предоставляет.
K>просто я так понял, что если сказано "наследники должны определять данное поведение", то эта обязанность закреплена контрактом(абстрактным методом)..
Не понял вышесказанное.

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



K>Тогда, с точки зрения этих законов, его решение признается нормальным, а те кто его "ткнули носом" — несведующими. или нет? а какие тогда проблемы в этом решении?

K>1. параллельные иерархии, здесь канают. или нет?
Параллельные иерархии типов? Почему бы и нет.
K>2. узко типизированные связи между потомками тоже. я кстати, вообще не понимаю, почему seas считает это не кошерным?
+1

В данном случае у нас есть некоторая система перехода между реляционной моделью и объектной. Реляционка медленна и не полиморфна и плохо относится к транзитивным замыканиям. Объектная быстрая и полиморфна. Нужно просто найти некоторую середину чтобы было удобно, и эффективно. Hibernate в данном случае хороший помощник.
Re[15]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 09:32
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>>>
GZ>>>void Method()
GZ>>>{
GZ>>>    if (this is Obj1)
GZ>>>       ((Obj1).Method2();
GZ>>>    else
GZ>>>       ((Obj2).Method3();
GZ>>>}
GZ>>>

GZ>Это значит что если появился наследник Obj3 — то этот метод будет давать ошибку, смысл которой можно получить только через трассировку.
а если написать:

if (this is Obj1)
    ((Obj1).Method2();
else if (this is Obj2)
    ((Obj2).Method3();

ошибки не будет

GZ>А если это последовательность вызовов методов как базового класса так и наследников?

так:

class Obj
{
    virtual void Method()
    {
    ExtractedMethod1();
    ExtractedMethod2():
    }

    virtual void ExtractedMethod1()
    {
    ...
    }

    abstract void ExtractedMethod2()
    {
    ...
    }
}

class Obj1 : Obj
{
    override void Method()
    { 
        // тело Method2
    }

    override void ExtractedMethod1()
    {
    ...
    }

    void ExtractedMethod2()
    {
    ...
    }

}

class Obj2 : Obj
{
    override void Method()
    { 
        // тело Method3
    }

    void ExtractedMethod2()
    {
    ...
    }

}


GZ>А если у нас появляется новый наследник у которого часть поведения эквивалентна Obj1 а другая часть эквивалентна Obj2?

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

K>>просто я так понял, что если сказано "наследники должны определять данное поведение", то эта обязанность закреплена контрактом(абстрактным методом)..

GZ>Не понял вышесказанное.
GZ>

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

так вроде же интерфейс поведения уже реализован в самом наследуемом классе, а если должен быть реализован наследником, делают абстрактные методы . а дополнение интерфейса не является обязательным и не должно быть доступно базовому — в чём и состоит главный тезис!

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

лучшее решение — объектная база данных!!!!!!! реляционка должна умереть!
Re[8]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 09:56
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Можно ввести понятие фиктивной группы или же вообще отказаться от явного декларирования различий между Person и Group. Если есть Role, то и должен быть Actor, который играет эту роль. А уж что это за actor — person или group — дело десятое.

не совсем очевидно, мне например, как это ложится на код?

K>>в Approval нужен еще User dueApprover, который так же зависит от вида сущности. куда его приткнуть?

КЛ>Тут бесполезно что-либо гадать, пока seas не опишет обязанности своих классов и то, что они должны делать.
хитрый уход от ответа
обязанности не важны — это модель данных, а не реализация паттерна Domain Model. тут важны данные!
кстати, не знаю почему это так... вроде у Фаулера тоже использовались POJO, что у них не может быть методов? преимущество ООП как раз и заключается в объединении данных и поведения

K>>кроме того, seas изначально сказал, что использует не базовый тип поля для контроля. — знание, что Role — это PersonalRole, у которого видимо свой набор полей, ещё дорогово стоит!

КЛ>В том-то и различие в подходах. Если классы Role, PersonalRole и GroupRole выступают просто в виде наборов полей, то группировать можно, как угодно. Потому что группируй — не группируй, а все равно получишь... неудобное решение.
а вчём, позвольте узнать, оно не удобно? работает же его схема... это модель данных! seas'а устраивает, что конкретно не так?
КЛ>Если же считать, что все роли обладают одинаковыми обязанностями (просто реализации этих обязанностей у них разные), то совершенно неважно знать, какая это роль — PersonalRole или GroupRole.
это у них будут одинаковые интерфейсы, интерфейсы — это поведение, а у нас модель данных и отстаньте(шучу)
Re[9]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 19.10.07 11:32
Оценка:
Здравствуйте, kejroot, Вы писали:

K>не совсем очевидно, мне например, как это ложится на код?

Вместо Group роль использует Actor, который может быть либо Person, либо Group.

K>хитрый уход от ответа

K>обязанности не важны — это модель данных, а не реализация паттерна Domain Model. тут важны данные!
Как раз-таки важны именно обязанности. Смотрите, например, здесь
Автор: Кирилл Лебедев
Дата: 18.10.07
.

K>кстати, не знаю почему это так... вроде у Фаулера тоже использовались POJO, что у них не может быть методов? преимущество ООП как раз и заключается в объединении данных и поведения

Согласен. Но данные нужно подбирать и группировать под поведение, а не наоборот.

K>а вчём, позвольте узнать, оно не удобно? работает же его схема... это модель данных! seas'а устраивает, что конкретно не так?

Если бы seas устраивало его решение, вряд ли бы он обратился за помощью. Основные недостатки см., например, здесь
Автор: Кирилл Лебедев
Дата: 17.10.07
.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[10]: Как правильно реализовать Domain Model?
От: kejroot  
Дата: 19.10.07 13:44
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, kejroot, Вы писали:


K>>не совсем очевидно, мне например, как это ложится на код?

КЛ>Вместо Group роль использует Actor, который может быть либо Person, либо Group.

K>>хитрый уход от ответа

K>>обязанности не важны — это модель данных, а не реализация паттерна Domain Model. тут важны данные!
сказано, с долей иронии между прочим..
КЛ>Как раз-таки важны именно обязанности. Смотрите, например, здесь
Автор: Кирилл Лебедев
Дата: 18.10.07
.


K>>кстати, не знаю почему это так... вроде у Фаулера тоже использовались POJO, что у них не может быть методов? преимущество ООП как раз и заключается в объединении данных и поведения

КЛ>Согласен. Но данные нужно подбирать и группировать под поведение, а не наоборот.
помойму, первостепенное значение имеет смысл, вкладываемый в то и в другое — согласованность с концепцией, представляемой классом

K>>а вчём, позвольте узнать, оно не удобно? работает же его схема... это модель данных! seas'а устраивает, что конкретно не так?

КЛ>Если бы seas устраивало его решение, вряд ли бы он обратился за помощью.
seas спросил:

Но я считаю Domain Model — моделью данных, а не логики — ведь все-же она состоит из POJO.
Так вот прав-ли я?

дальше, предполагая, что прав:

Действитель-но ли можно считать такой не объектно ориентированный дизайн — вполне приемлемым для модели данных?

мы с GlebZ'ом ответили на этот вопрос положительно.
КЛ>Основные недостатки см., например, здесь
Автор: Кирилл Лебедев
Дата: 17.10.07
.

Здесь — авторитетно заявлена серьёзная ошибка. а в чём она состоит?
в том, видимо, что seas таки не прав, пользуясь, только моделью данных?

Что можно почитать из теории по этому поводу?

мне кажется, нужно повнимательнее взглянуть на Domain Model, а еще лучше в книге, где сказано, что она включает методы работы с данными палюбому!

но! вдруг в его приложении действительно можно обойтись таким решением. зачем усложнять, если можно не?
Re[4]: Как правильно реализовать Domain Model?
От: seas  
Дата: 20.10.07 04:14
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, seas, Вы писали:


S>>Первое дерево, с самыми долгоживущими объектами (буквально задаются до старта системы):

КЛ>А какие обязанности у Ваших классов? За что отвечает группа классов Role? За что отвечают группы Assignment и Approval?
Приложение, буквально, реализует маленькую часть документооборота — документы последовательно получают подтверждение со стороны разных людей в иерархии организации. Бизнес-процесс таков, что сначала документ получает подтверждение в соответствии с иерархией организации, далее в некоторый момент получает подтверждение со стороны фин. манагера бизнес единицы (например отдела) и дальше идет в соответствии с упорядоченным сетом ролей: CFO, за ним COO. Соответственно, мне нужно разделить роли на просто роли (обычный работник, CFO, COO), и роли, привязанные к бизнес единице (фин. манагер). Мне очень хочется чтобы база данных это навязывала и если кто-то пытается положить туда мусор — возвращала exception.

В моей модели:
Role — статический тип роли, заданный с начала работы системы.
Assignment — задает relationship между пользователем системы и ролью (у юзера может быть несколько ролей).
Approval — задает так или иначе следующего подтверждающего, им может быть как конкретный человек (или несколько людей) или задана роль (просто роль или роль в привязке к бизнес-единице, т.е. без указания конкретного человека, но с указанием роли и отдела).

S>>1. abstract class Role;

S>>2. class RolePersonal extends Role;
S>>3. class RoleOverGroup extends Role;
КЛ>Есть предложения реорганизовать Вашу иерархию таким образом:

КЛ>
КЛ>class Role {...};
КЛ>class PersonalRole : public Role {...};
КЛ>class GroupRole : public Role {...};

КЛ>class Assignment
КЛ>{
КЛ>   User * m_pUser;
КЛ>   Group * m_pGroup;
КЛ>   Role * n_pRole;
КЛ>};

КЛ>class Approval
КЛ>{
КЛ>   Document * m_pDocument;
КЛ>   Role * m_pRole;
КЛ>   Group * m_pGroup;
КЛ>};
КЛ>

Таковой может быть логика, но должна-ли быть таковой модель данных? Ведь в вашем предложении модель данных, не предотвращает inconsistency. В моей иерархии, такие классы как ApprovalPathPersonal и RolePersonal идут вместе, и работают вместе, модель данных не допускает их смешение. В вашей модели, случай когда ApprovalPathPersonal ссылается на RoleGroup может считаться вполне нормальным. Причем такого рода ошибка в данных (а следовательно в логике занесения данных) выявится на этапе использования а не занесения, система должна будет проверять все эти случаи (самое тупое — используя instanceof), а что делать системе если такого рода ошибка встретилась в background процессе — валить ошибку в лог, в надежде что кто-то будет там рыться — по-моему все это не очень хорошо. Пусть уж идет проверка в момент занесения данных в базу с моментальным вынесением приговора на экран пользователю.
Re[8]: Как правильно реализовать Domain Model?
От: seas  
Дата: 20.10.07 04:34
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, kejroot, Вы писали:


K>>правда не совсем понятно какие изменения между первоначальным:

КЛ>Никаких — просто поменял названия на, как мне кажется, более уместные.

K>>Но оно есть! поле m_pGroup должно быть заполнено или нет в зависимости от "различия между сущностями". предлагаю перенести его в класс GroupRole.

КЛ>Можно ввести понятие фиктивной группы или же вообще отказаться от явного декларирования различий между Person и Group. Если есть Role, то и должен быть Actor, который играет эту роль. А уж что это за actor — person или group — дело десятое.
Персональная роль — является атрибутом пользователя просто сама по себе (например, пользователь имеет роль COO), групповая роль — это когда пользователь имеет роль в привязке к группе (бизнес единице, такой как отдел) — и не имеет эту роль в привязке к другим группам (фин. манагер для какого-то отдела). Соответственно, такого рода знания используются в документообороте когда смотрится, кто-же следующий по бизнес-процессу должен поставить подтверждение на документе.

K>>в Approval нужен еще User dueApprover, который так же зависит от вида сущности. куда его приткнуть?

КЛ>Тут бесполезно что-либо гадать, пока seas не опишет обязанности своих классов и то, что они должны делать.
описал в соседнем посте, если кратенько:
RolePersonal — роли пользователей как самих по себе (CFO, COO, Buyer, Receiver).
RoleGroup — роль требующая привязки к бизнес-единице (фин. манагер и его помошник)
AssignmentPersonal — назначение персональной роли пользователю.
AssignmentOverGroup — назначение роли над группой (с указанием конкретной группы)
ApprovalPathPersonal — указывает какой конкретно пользователь должен делать approve следующим.
ApprovalPathOverGroup — указывает от людей с какой ролью в рамках какой бизнес-единицы (с указанием этой единицы) требуется approve.

K>>кроме того, seas изначально сказал, что использует не базовый тип поля для контроля. — знание, что Role — это PersonalRole, у которого видимо свой набор полей, ещё дорогово стоит!

КЛ>В том-то и различие в подходах. Если классы Role, PersonalRole и GroupRole выступают просто в виде наборов полей, то группировать можно, как угодно. Потому что группируй — не группируй, а все равно получишь... неудобное решение. Если же считать, что все роли обладают одинаковыми обязанностями (просто реализации этих обязанностей у них разные), то совершенно неважно знать, какая это роль — PersonalRole или GroupRole.
Re[10]: Как правильно реализовать Domain Model?
От: seas  
Дата: 20.10.07 04:37
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, kejroot, Вы писали:


K>>не совсем очевидно, мне например, как это ложится на код?

КЛ>Вместо Group роль использует Actor, который может быть либо Person, либо Group.

K>>хитрый уход от ответа

K>>обязанности не важны — это модель данных, а не реализация паттерна Domain Model. тут важны данные!
КЛ>Как раз-таки важны именно обязанности. Смотрите, например, здесь
Автор: Кирилл Лебедев
Дата: 18.10.07
.


K>>кстати, не знаю почему это так... вроде у Фаулера тоже использовались POJO, что у них не может быть методов? преимущество ООП как раз и заключается в объединении данных и поведения

КЛ>Согласен. Но данные нужно подбирать и группировать под поведение, а не наоборот.

K>>а вчём, позвольте узнать, оно не удобно? работает же его схема... это модель данных! seas'а устраивает, что конкретно не так?

КЛ>Если бы seas устраивало его решение, вряд ли бы он обратился за помощью. Основные недостатки см., например, здесь
Автор: Кирилл Лебедев
Дата: 17.10.07
.

В принципе, меня устраивает это решение, я вижу в нем множество преимуществ. Но интересно знать как такие задачи решают другие.
Re[5]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 22.10.07 05:43
Оценка:
Здравствуйте, seas, Вы писали:

S>Приложение, буквально, реализует маленькую часть документооборота — документы последовательно получают подтверждение со стороны разных людей в иерархии организации.

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

S>Role — статический тип роли, заданный с начала работы системы.

Тем не менее, не ясно, что делает именно класс Role? Какие функции можно у него вызвать?

S>Assignment — задает relationship между пользователем системы и ролью (у юзера может быть несколько ролей).

Правильно ли я понимаю, что основная задача класса Assignment — вернуть по юзеру его роль или роли? Т.е. будет ли справедливым код?

Assignment theAssignment = new Assignment();
User theUser = new User(some_data);
//...
Role theRole = theAssignemt.GetRole(theUser);


Получив роль, что мы делаем дальше? Какие функции можно из нее вызвать? И нужно ли получение роли делегировать классу Assignment? Нельзя ли запросить роль пользователя у класса User?

User theUser = new User(some_data);
//...
Role theRole = theUser.GetRole(theUser);


S>Approval — задает так или иначе следующего подтверждающего, им может быть как конкретный человек (или несколько людей) или задана роль (просто роль или роль в привязке к бизнес-единице, т.е. без указания конкретного человека, но с указанием роли и отдела).

Правильно ли я понимаю, что единственная задача класса Approval — это вернуть следующего подтверждающего? Т.е. справедлив такой код:

Approval theApproval = new Approval();
//...
Approver theApprover = theApproval.GetNextApprover();
// где theApprover - это либо User, либо Role.


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

S>Таковой может быть логика, но должна-ли быть таковой модель данных? Ведь в вашем предложении модель данных, не предотвращает inconsistency. В моей иерархии, такие классы как ApprovalPathPersonal и RolePersonal идут вместе, и работают вместе, модель данных не допускает их смешение. В вашей модели, случай когда ApprovalPathPersonal ссылается на RoleGroup может считаться вполне нормальным.

Предлагаю задачу согласованности данных рассмотреть отдельно. Это отдельная задача, и у нее есть свои способы решения.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[9]: Как правильно реализовать Domain Model?
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 22.10.07 05:53
Оценка:
Здравствуйте, seas, Вы писали:

S>Персональная роль — является атрибутом пользователя просто сама по себе (например, пользователь имеет роль COO), групповая роль — это когда пользователь имеет роль в привязке к группе (бизнес единице, такой как отдел) — и не имеет эту роль в привязке к другим группам (фин. манагер для какого-то отдела).

Простите, если мой вопрос покажется глупым, но мне непонятно, зачем разделять роль на роль саму по себе и роль в привязке к бизнес-единице?
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[10]: Как правильно реализовать Domain Model?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.10.07 05:59
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, seas, Вы писали:


S>>Персональная роль — является атрибутом пользователя просто сама по себе (например, пользователь имеет роль COO), групповая роль — это когда пользователь имеет роль в привязке к группе (бизнес единице, такой как отдел) — и не имеет эту роль в привязке к другим группам (фин. манагер для какого-то отдела).

КЛ>Простите, если мой вопрос покажется глупым, но мне непонятно, зачем разделять роль на роль саму по себе и роль в привязке к бизнес-единице?
Я так понимаю, что имеется в виду следующее: роль "начальник отдела" сама по себе не дает прав на доступ к ресурсам. Нужна роль "начальник такого-то отдела".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.