Здравствуйте, C0s, Вы писали:
C0s>в ситуации с разными источниками данных унификация такого рода (когда в тексте программы обращения выглядят одинаковыми) мне кажется вредной, т.к. поощряет программистов-пользователей такого уровня DAO не задумываться, откуда данные. следствием этого будут ошибки, которые исправить будет нелегко.
Скорее наоборот. Лишние раздумывание над ненужными подробностями и вытягивание этих подробностей на более высокий слои как раз и ведет к ошибкам.
Логика того как в какой последовательности и что вызывать как раз и должна быть сосредоточена в DAL, собственно, это одна из его основных задач. Код который вызывает DAL это заботить не должно.
C0s>видеть эту разницу в тексте — фундаментально для адекватной обработки ошибочных и полуошибочных ситуаций и для правильной расстановки вызовов, например, когда часть данных можно получить перед транзакцией БД, тем самым, не удлиняя её.
Пусть этим DAL занимается, это как раз его забота. Именно для этого служит класс, о необходимости которого ты спрашивал в первом сообщении топика.
Здравствуйте, IB, Вы писали:
C0s>>в ситуации с разными источниками данных унификация такого рода (когда в тексте программы обращения выглядят одинаковыми) мне кажется вредной, т.к. поощряет программистов-пользователей такого уровня DAO не задумываться, откуда данные. следствием этого будут ошибки, которые исправить будет нелегко. IB>Скорее наоборот. Лишние раздумывание над ненужными подробностями и вытягивание этих подробностей на более высокий слои как раз и ведет к ошибкам. IB>Логика того как в какой последовательности и что вызывать как раз и должна быть сосредоточена в DAL, собственно, это одна из его основных задач. Код который вызывает DAL это заботить не должно.
не соглашусь. к примеру, пусть по факту обработки use-case "обращение клиента", надо сначала дёрнуть legacy-систему, потом поковыряться в своей БД, после чего вызвать web-service отсылки e-mail.
для меня в такой ситуации API legacy-системы будет отделено во всех смыслах от DAL к собственной БД, и уж тем более оба будут отделены от API почтового web-сервиса. и располагаться на одном уровне доступных сервисов и внешних систем.
а вот на уровне бизнес-логики обработки use-case'а будет явно прописано, что и в каком порядке вызывается и как это сочетается с транзакциями, например, в зависимости от того, поддерживает ли API к legacy-системе интеграцию с глобальными транзакциями или нет.
IB>Пусть этим DAL занимается, это как раз его забота. Именно для этого служит класс, о необходимости которого ты спрашивал в первом сообщении топика.
вот в приведенном примере это как раз забота алгоритма реализации use-case'а, но никак не DAL
Здравствуйте, IB, Вы писали:
IB>Проблема в том, что при таком подходе весь код оказывается гвоздями прибит к Гибернейту.
в моих приложения гвоздями прибивается к hibernate'у не весь код, а только реализации тех use cases, которые взаимодействуют с БД, причём это не касается уровня презентации, который hibernate и прочие внешние системы у меня никогда не видит.
при этом абстрагироваться в реализации use-cases от hibernate, который как тул работы с БД меня полностью устраивает, я не вижу смысла. т.е. причина могла бы быть одна — ожидаемое появление через N месяцев brandNewHibernate, помноженное на необходимость развивать проект в течение долгих лет.
IB>По сути гибернейт диктует и архитектуру приложения и реализацию и все остальное. Получается уже программирование на гибернейте, а не на языке программирования...
только в реализации use cases, большой уровень презентации и прочего ничего про это не знает
IB>Вынесение же работы с БД в отдельный класс позволяет держать подобный код в резервации, что положительно сказывается на поддержке и понятности.
лишний код далеко не всегда положительно сказывается на здоровье проекта
Здравствуйте, C0s, Вы писали:
C0s>в моих приложения гвоздями прибивается к hibernate'у не весь код, а только реализации тех use cases, которые взаимодействуют с БД, причём это не касается уровня презентации, который hibernate и прочие внешние системы у меня никогда не видит.
Отлично, а что видит уровень презентации и БЛ?
C0s>при этом абстрагироваться в реализации use-cases от hibernate, который как тул работы с БД меня полностью устраивает, я не вижу смысла.
DAL — это не только БД.
C0s>только в реализации use cases, большой уровень презентации и прочего ничего про это не знает
И как это отделено друг от друга?
C0s>лишний код далеко не всегда положительно сказывается на здоровье проекта
Это если он лишний. А если для дела, то как правило положительно.
Здравствуйте, C0s, Вы писали:
C0s>к примеру, пусть по факту обработки use-case "обращение клиента", надо сначала дёрнуть legacy-систему, потом поковыряться в своей БД, после чего вызвать web-service отсылки e-mail.
Ключевой вопрос — это бизнес-процесс такой или это реализация DAL?
C0s>для меня в такой ситуации API legacy-системы будет отделено во всех смыслах от DAL к собственной БД, и уж тем более оба будут отделены от API почтового web-сервиса.
В каких всех смыслах?
Если это такой бизнес-процесс, то у нас есь ServiceLayer, который там же где и DAL и спроектирован таким же образом. И опять-таки вызывающий код совршенно не парит, к какой-такой Legacy сестеме он обращается и что он вообще опращается к legacy — это не его головная боль, равно как и особенности реализации этого обращения. Просто есть некий метод, а уж легаси он там или не очень — дело десятое.
Так же его не парит, как именно реализован сервис рассылок, веб-сервис ли это, очередь или еще что, это просто некая конструкция оборудованная соответствующим API. То же самое относится и к БД/DAL, я знать не знаю гибернейт там или еще что и знать не хочу — это особенность реализации, которая не должна влиять на публичный контракт какого-то ни было слоя.
Далее, в бизнес-слое просто отрабатывается соответствующий сценарий обработки клиентского запроса не заморачиваясь вопросами эффективности вызовов и прочей низкоуровневой требухи. Забота бизнес слоя — исключительно правильность логики.
Если же обращение к легаси системе часть механизма хранения данных, то это все закатываетсяв DAL (естествнно, каждый аспект в свою часть), а наружу торчит единственный метод "сохранить запрос клиента", с соответствующим набором параметров. И внешний код не заботит как это будет сделано, что там пойдет через легаси, а что нет.
Отправка мыла — это всегда отдельный сервис, единственное что может сделать DAL — это выставить соответствующие признаки в БД, куда и что отправлять.
C0s>а вот на уровне бизнес-логики обработки use-case'а будет явно прописано, что и в каком порядке вызывается и как это сочетается с транзакциями, например, в зависимости от того, поддерживает ли API к legacy-системе интеграцию с глобальными транзакциями или нет.
Разбираться кто там поддерживает транзакции, а кто нет — это не забота бизнес-логики. Забота BL — это только сама логика и ничего кроме логики. Если легаси система транзакций не поддерживает, а в БЛ это надо, значит DAL должен реализовать соответствующую обертку чтобы все заработало.
C0s>вот в приведенном примере это как раз забота алгоритма реализации use-case'а, но никак не DAL
Это зависит от задач которые решает данный пример.
Здравствуйте, IB, Вы писали:
C0s>>в моих приложения гвоздями прибивается к hibernate'у не весь код, а только реализации тех use cases, которые взаимодействуют с БД, причём это не касается уровня презентации, который hibernate и прочие внешние системы у меня никогда не видит.
IB>Отлично, а что видит уровень презентации и БЛ? IB>И как это отделено друг от друга?
реализация usecases — это и есть БЛ. естественно, что уровень презентации видит БЛ-api, и оба зависят от структур данных, с помощью которых производится обмен информацией между ними. эти структуры можно назвать POJO, можно DTO, суть не меняется. просто эти структуры не обязаны повторять структуры DAL с одной стороны, с другой стороны они могут помогать переносить информацию между узлами по сети в ситуации удалённых вызовов.
Здравствуйте, C0s, Вы писали:
C0s>лишний код далеко не всегда положительно сказывается на здоровье проекта
а не сказывается ли такое вот размазывание Hibernate-вызовов на появление того самого лишнего кода? Ведь что такое DAO? Абстракция, призваная инкапсулировать в себя детали работы с DAL. А в больших системах наблюдаются некторые шаблонные подходы к этим деталям, которые вполне могуть быть выделены в базовые классы и использоваться повсеместно. Пример этому — тот самый GenericDAO, в котором могут быть обобщены наиболее часто используемые запросы. Если этого не делать, то по любому появятся всякие статик-хелперы, реализующие те самые детали, причем завязываеющие БЛ на себя уже статически. К тому же при использовании GenericDAO получается еще один бонус — проверка типов на этапе компилирования, без необходимости каста в местах вызова.
Здравствуйте, IB, Вы писали:
C0s>>к примеру, пусть по факту обработки use-case "обращение клиента", надо сначала дёрнуть legacy-систему, потом поковыряться в своей БД, после чего вызвать web-service отсылки e-mail. IB>Ключевой вопрос — это бизнес-процесс такой или это реализация DAL?
возможно, имеет место терминологическая путаница, ибо я это называю слоем БЛ, и никак уж не DAL.
для меня слой БЛ — это слой, где реализуются use cases.
C0s>>для меня в такой ситуации API legacy-системы будет отделено во всех смыслах от DAL к собственной БД, и уж тем более оба будут отделены от API почтового web-сервиса. IB>В каких всех смыслах?
они друг от друга не зависят, их использует вышестоящий уровень — уровень реализации use cases, по требованиям к которому в приведённом абстракном примере пришлось проинтегрироваться с legacy-системой, и реализованным студентом Пупкиным набором web-сервисов.
C0s>>а вот на уровне бизнес-логики обработки use-case'а будет явно прописано, что и в каком порядке вызывается и как это сочетается с транзакциями, например, в зависимости от того, поддерживает ли API к legacy-системе интеграцию с глобальными транзакциями или нет.
IB>Разбираться кто там поддерживает транзакции, а кто нет — это не забота бизнес-логики. Забота BL — это только сама логика и ничего кроме логики.
я не согласен именно с пренебрежением относительно забот насчет транзакций. где-то ведь возникает демаркация транзакций, явная или декларативная. реализация каждого use case, по моим представлениям, идеальный кандидат на работу в рамках транзакции, но с поправками на то, какие нетранзакционные сервисы ему приходится дёргать.
IB>Если легаси система транзакций не поддерживает, а в БЛ это надо, значит DAL должен реализовать соответствующую обертку чтобы все заработало.
если она не поддерживает транзакций, то ни в коем случае этот факт не должен быть скрыт от определенного уровня. я так понял, ты этот уровень не называешь БЛ, а для меня он в любом случае выше, чем DAL.
попробую опять пояснить, пусть пример с "обращением клиента" и абстрактен:
я подразумевал, что это — бизнес use case, т.е. на презентационном уровне была форма, которую пользователь заполнил и нажал кнопку. по этой кнопке данные валидируются и передаются обсуждаемой реализации этого use case. и требование интегрироваться с legacy — не прихоть программера, а одно из дебильных бизнес-требований к реализации большей части use cases проекта.
вот это обилие слов "бизнес" ну никак мне не дает возможности назвать этот уровень DAL или high-level DAL. для меня это БЛ.
Здравствуйте, Lucker, Вы писали:
L>а не сказывается ли такое вот размазывание Hibernate-вызовов на появление того самого лишнего кода? Ведь что такое DAO? Абстракция, призваная инкапсулировать в себя детали работы с DAL.
я не могу сказать, что у меня что-то размазывалось. как правило, у меня это выглядит как набор интерфейсов по одному на каждую часть предметной области (разбиение на части делается по каким-то признакам группировки use-cases и призвано для упрощения работы с сущностями системы).
еще я начинаю думать, что то, что у меня называется низко- и среднеуровневой логикой, ты (и IB, если я правильно понял) называешь DAL. просто некоторые простые манипуляции типа создания объекта или его обновления уже могут реализовывать самостоятельные бизнес-use cases.
при этом сложная БЛ у меня базируется на упомянутой низко- и среднеуровневой логике, и в ней hibernate (или DAO) не упоминается вообще — работа ведётся через API, предоставленное с более низких уровней реализации БЛ
L>А в больших системах наблюдаются некторые шаблонные подходы к этим деталям, которые вполне могуть быть выделены в базовые классы и использоваться повсеместно. Пример этому — тот самый GenericDAO, в котором могут быть обобщены наиболее часто используемые запросы.
видимо, я пока пишу маленькие системы, т.к. я не вижу путей к обоющению.
простой пример: реализация постраничных фильтрованных запросов. разные сущности — разные фильтры, принципиально разные запросы и никакого обобщения.
Здравствуйте, C0s, Вы писали:
C0s> эти структуры можно назвать POJO, можно DTO, суть не меняется. просто эти структуры не обязаны повторять структуры DAL с одной стороны, с другой стороны они могут помогать переносить информацию между узлами по сети в ситуации удалённых вызовов.
Угу. Только как правило оказывается, что DTO практически один в один таки повторяют объекты DAL. Вот у нас и получается некая бизнес-сущность, с которой удобно работатьи БД, и БЛ и презеннтационному слою, и по сети ее пулять.
Очень удобно и никаких лишних преобразований, но это уже другой вопрос...
Я собственно к тому, что слой бизнес-логики у тебя помимо собственно обработки use-case'ов занимается еще и преобразованием объектов DAL в объекты для презентационного слоя и работает с гибернейтом.. Так?
Здравствуйте, IB, Вы писали:
C0s>> эти структуры можно назвать POJO, можно DTO, суть не меняется. просто эти структуры не обязаны повторять структуры DAL с одной стороны, с другой стороны они могут помогать переносить информацию между узлами по сети в ситуации удалённых вызовов.
IB>Угу. Только как правило оказывается, что DTO практически один в один таки повторяют объекты DAL. Вот у нас и получается некая бизнес-сущность, с которой удобно работатьи БД, и БЛ и презеннтационному слою, и по сети ее пулять.
я тут выше уже писал — у меня они разные. похожие, но разные =)
IB>Очень удобно и никаких лишних преобразований, но это уже другой вопрос...
я не боюсь этих лишних преобразований, т.к. более строгие DTO позволяют минимизировать всякие ошибки в коде более высокого уровня. потом, те объекты, которые имеют очень сильное сходство я просто поднимаю выше, но всегда через урезающую обёртку — всё для той же строгости.
т.е. для меня кажется нормальным, что объекты, использующиеся в деталях реализации одного уровня не экспозируются на вышестоящий.
IB>Я собственно к тому, что слой бизнес-логики у тебя помимо собственно обработки use-case'ов занимается еще и преобразованием объектов DAL в объекты для презентационного слоя и работает с гибернейтом.. Так?
простые методы БЛ — да,
сложные же методы БЛ являются либо композицией простых, т.е. сами по себе не работают уже с hibernate'ом etc
Здравствуйте, C0s, Вы писали:
C0s>Здравствуйте, Lucker, Вы писали:
L>>А в больших системах наблюдаются некторые шаблонные подходы к этим деталям, которые вполне могуть быть выделены в базовые классы и использоваться повсеместно. Пример этому — тот самый GenericDAO, в котором могут быть обобщены наиболее часто используемые запросы.
C0s>видимо, я пока пишу маленькие системы, т.к. я не вижу путей к обоющению. C0s>простой пример: реализация постраничных фильтрованных запросов. разные сущности — разные фильтры, принципиально разные запросы и никакого обобщения.
вот как раз из попытки обобщить реализацию такого примера первоначальный вопрос и появился. Вроде, неплохо обобщилось.
Все сущности в системе унаследованы от общего класса Entity, с Integer id полем. Значит, сущности уже можно искать по id, или набору id. Далее, в системе есть пользователи (User), каждый из которых может принадлежать некоторому региону. Значит пользователей уже можем искать по id и по региону. Далее, пользователи делятся на два типа: StaffUser, каждый из которых выполняет свою роль (можем искать по id, региону и роли), и Client, имеющие дополнительный классификатор Type(можем искать по id, региону и типу). Ну и так далее. Для каждой сущности есть интерфей EntityQueryParameters
public interface EntitiesQueryParameters {
Collection<? extends Integer> getIds();
}
public interface UserQueryParameters extends EntitiesQueryParameters {
Region getRegion();
}
public interface ClientsQueryParameters extends UserQueryParameters {
Type getType();
}
public interface StaffQueryParameters extends UserQueryParameters {
Role getRole();
}
Ну и теперь ДАО:
public abstract class AbstractEntitiesQuerySupportDAO<E extends Entity, T extends EntitiesQueryParameters>{
public List<? extends E> findEntities(final T queryParameters, final int startFrom, final int count, final SortDefinition... sortDefinitions) {
return getHibernateTemplateEx().executeFind(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
final Criteria[] criteria = createCriteria(session, queryParameters);
if (criteria == null) {
return Collections.emptyList();
}
if (startFrom != 0) {
criteria[0].setFirstResult(startFrom);
}
if (count >= 0) {
criteria[0].setMaxResults(count);
}
return setupOrder(criteria[0], sortDefinitions).list();
}
});
}
protected Criteria[] createCriteria(final Session session, final T filter) {
final Criteria[] criteria = new Criteria[]{session.createCriteria(getEntityName())};
if (filter.getIds() != null) {
if (filter.getIds().size() == 0) {
return null;
}
criteria[0].add(Restrictions.in("id", filter.getIds()));
}
return criteria;
}
}
что делают остальные ДАО, так это переопределяют createCriteria, добавляя в него свои критерии
public abstract class UserDAOImpl<A extends User, P extends UserQueryParameters>
extends AbstractEntitiesQuerySupportDAO<A, P> implements UserDAO<A, P> {
@Override
protected Criteria[] createCriteria(final Session session, final P filter) {
final Criteria[] criteria = createCriteria(session, filter);
if (criteria == null) {
return null;
}
if (filter.getRegion() != null) {
criteria[0].add(Restrictions.eq("region", filter.getRegion()));
}
return criteria;
}
}
public class StaffDAOImpl extends UserDAOImpl<StaffUser, StaffQueryParameters> implements StaffDAO {
@Override
protected Criteria[] createCriteria(final Session session, final StaffQueryParameters filter) {
final Criteria[] criteria = super.createCriteria(session, filter);
if (criteria == null) {
return null;
}
if (filter.getRole() != null) {
criteria[0].add(Restrictions.eq("role", filter.getRole()));
}
return criteria;
}
}
public class ClientDAOImpl extends UserDAOImpl<Client, ClientsQueryParameters> implements ClientDAO {
@Override
protected Criteria[] createCriteria(final Session session, final ClientsQueryParameters filter) {
final Criteria[] criteria = super.createCriteria(session, filter);
if (criteria == null) {
return null;
}
if (filter.getType() != null) {
criteria[0].add(Restrictions.eq("type", filter.getType()));
}
return criteria;
}
}
И так далее. Для клиента есть другие интерфейсы,
public interface EntitiesQuery<T extends EntitiesQuery, E extends Entity> {
T withId(Integer id);
T withIds(Collection<? extends Integer> id);
List<? extends E> find(final SortDefinition ... definitions);
List<? extends E> find(int startFrom, int count, final SortDefinition ... definitions);
}
public interface UserQuery<T extends UserQuery, A extends User> extends EntitiesQuery<T, A> {
T inRegion(Region region);
}
public interface StaffQuery extends UserQuery<StaffQuery, StaffUser> {
StaffQuery whithRole(Role role);
}
public interface ClietnQuery extends UserQuery<ClietnQuery, Client> {
ClietnQuery whithType(Type type);
}
createStaffQuery() — псевдовызов, возвращающий нужный запрос в виде интерфейса.
Все детали выполения запросов сосредоточены в DAO, Query — тупо собирают параметры, и передают их в ДАО, а клиент работает с жестко типизироваными методами.
Здравствуйте, C0s, Вы писали:
C0s>я не согласен именно с пренебрежением относительно забот насчет транзакций. где-то ведь возникает демаркация транзакций, явная или декларативная. реализация каждого use case, по моим представлениям, идеальный кандидат на работу в рамках транзакции, но с поправками на то, какие нетранзакционные сервисы ему приходится дёргать.
use-case не должно заботить поддерживает нижележащий уровень транзакцию или нет. Если транзакция нужна, значит этот уровень обязан ее поддержать. Не надо при реализации логики заморачиваться на особенности реализации нижележащего кода.
C0s>я подразумевал, что это — бизнес use case, т.е. на презентационном уровне была форма, которую пользователь заполнил и нажал кнопку. по этой кнопке данные валидируются и передаются обсуждаемой реализации этого use case. и требование интегрироваться с legacy — не прихоть программера, а одно из дебильных бизнес-требований к реализации большей части use cases проекта.
У нас есть в DAL два метода Native и Legacy. use-case обработки запроса заключается в последовательном вызове методов Legacy и Native.
Так вот БЛ вызывает просто Method1 и Method2 — какой из них легаси и что он там поддерживает — не его забота. Главное что он реализовывает соответствующую функциональность, а уж как он это делает у него голова болеть не должна, хоть голубиной почтой.
Здравствуйте, C0s, Вы писали:
C0s>я тут выше уже писал — у меня они разные. похожие, но разные =)
Зря. Когда одинаковые — жить проще.
C0s>я не боюсь этих лишних преобразований, т.к. более строгие DTO позволяют минимизировать всякие ошибки в коде более высокого уровня.
И внести новые на этапе преобразований. Хрен редьки....
Здравствуйте, IB, Вы писали:
C0s>>я не боюсь этих лишних преобразований, т.к. более строгие DTO позволяют минимизировать всякие ошибки в коде более высокого уровня. IB>И внести новые на этапе преобразований. Хрен редьки....
не совсем,
1) эти объекты не так сложны в устройстве.
2) каждый объект используется в N местах. я предпочитаю контролировать M имплементаций объектов (инстанцирование которых собрано в небольшом количестве фабричных классов) вместо усиления контроля за M*N(m) мест их использования
Здравствуйте, IB, Вы писали:
IB>use-case не должно заботить поддерживает нижележащий уровень транзакцию или нет.
возможно, ты еще не видел, как при таком подходе делаются ошибки, приводящие к рассогласованности данных, о которой не идет правильной диагностики "наверх"
IB>Если транзакция нужна, значит этот уровень обязан ее поддержать. Не надо при реализации логики заморачиваться на особенности реализации нижележащего кода.
если транзакция нужна, но нижележащий код не может ее поддержать, это должно быть явно учтено (на текущем уровне), а не проигнорировано путём заглушек (на нижележащем уровне), имитирующих поддержку транзакции
IB>У нас есть в DAL два метода Native и Legacy. use-case обработки запроса заключается в последовательном вызове методов Legacy и Native. IB>Так вот БЛ вызывает просто Method1 и Method2 — какой из них легаси и что он там поддерживает — не его забота. Главное что он реализовывает соответствующую функциональность, а уж как он это делает у него голова болеть не должна, хоть голубиной почтой.
где объявлены и как реализованы Method1 и Method2?
Здравствуйте, C0s, Вы писали:
C0s>1) эти объекты не так сложны в устройстве.
Так зачем их тогда вообще трогать?
C0s>2) каждый объект используется в N местах. C0s> я предпочитаю контролировать M имплементаций объектов (инстанцирование которых собрано в небольшом количестве фабричных классов) вместо усиления контроля за M*N(m) мест их использования
Каждый объект содается ровно в одном месте и нигде не модифицируется. Сами объекты крайне просты, значит и контролировать их не надо, ни в N, ни в M случаях.
Здравствуйте, C0s, Вы писали:
C0s>возможно, ты еще не видел, как при таком подходе делаются ошибки, приводящие к рассогласованности данных, о которой не идет правильной диагностики "наверх"
Ага и вообще пороху не нюхал.. =)
Как описанная схема мешает правильной диагностике?
C0s>если транзакция нужна, но нижележащий код не может ее поддержать, это должно быть явно учтено (на текущем уровне),
Нет. Это означает что вышележащий код начинает лезть в особенности реализации нижележащего и при изменении кода DAL тебе придется перетряхивать весь проект и следить не рухнуло ли что.
C0s> а не проигнорировано путём заглушек (на нижележащем уровне), имитирующих поддержку транзакции
Имитируют они или нет — дело десятое.
C0s>где объявлены и как реализованы Method1 и Method2?
Объявлены — хоть в интерфейсе. Реализованы в DAL.
Здравствуйте, IB, Вы писали:
C0s>>спрашивается, зачем городить целый отдельный класс SomeObjectInDBDAO, если наиболее общеупотребительный случай с одинаковым успехом реализуется и без него?! IB>Проблема в том, что при таком подходе весь код оказывается гвоздями прибит к Гибернейту. По сути гибернейт диктует и архитектуру приложения и реализацию и все остальное. Получается уже программирование на гибернейте, а не на языке программирования...
То что ты ORMофоб мы уже и так знаем
IB>Вынесение же работы с БД в отдельный класс позволяет держать подобный код в резервации, что положительно сказывается на поддержке и понятности.
Зачем ее выносить в слое, который непосредственно с данными работает? Обычно у нас все равно появляются неявные связи с используемой системой ORM/DAL. Вот в интерфейсе слоя бизнес-логики и клиентского кода — деталей DALа не должно быть.
Здравствуйте, IB, Вы писали:
C0s>>1) эти объекты не так сложны в устройстве. IB>Так зачем их тогда вообще трогать?
что значит "трогать"?! я пишу про DTO, ты же утверждаешь, что их вообще использовать не надо
C0s>>2) каждый объект используется в N местах. C0s>> я предпочитаю контролировать M имплементаций объектов (инстанцирование которых собрано в небольшом количестве фабричных классов) вместо усиления контроля за M*N(m) мест их использования IB>Каждый объект содается ровно в одном месте и нигде не модифицируется. Сами объекты крайне просты, значит и контролировать их не надо, ни в N, ни в M случаях.
если это ORM-pojo, то он создаётся в большинстве случаев в недрах ORM и является модифицируемым (mutable)
именно поэтому я и пишу про DTO, которые у меня создаются мной там, где надо, оторваны от ORM и объектов, жизненным циклом котороых управляет ORM, и я являются настолько простыми, насколько это позволяет задача уровня презентации или что там еще бывает при работе с извлекаемыми данными.