И еще раз здравствуйте
Постараюсь быть кратким, хотя наверное не получится...
Читаю Нильссона, Фаулера и т.д. и т.п., пытаюсь поднять свой уровень, хочу понимать и грамотно уметь провести расслоение системы в типичном бизнес-приложении. Возникает много вопросов, вот некоторые из них:
Вопрос 1. А-ля "Передача connection'а vs получение (не открытие) connection'а где нужно"
Сам я сторонник возможности получения connection к БД в любом месте программы, а не передачи его из формы в форму, из метода в метод и т.д. Лично мне не нравится по всем слоям, классам и методам таскать объект соединения. Сначала я всем методам из DAL передавал коннекшен из кода форм, когда была простенькая архитектура — UI + DAL (к которому наверное можно отнести и классы сущностей типа Invoice, Customer и т.д. содержащие только поля). Особой бизнес-логики не было, потому что все было достаточно несложно и особая нужда в дополнительном слое бизнес-логики, бизнес-правил не чувствовалась. С развитием проекта и увеличением его сложности начинаешь понимать, что действительно нужен слой в котором были бы методы, инкапсулирующие внутри себе определенные бизнес-правила. Отвлекся. Вернемся к объекту соединения. С введением слоя бизнес-правил получается что объект соединения нужно сначала его передавать классам бизнес-логики, а те в свою очередь будут передавать его методам из DAL. Я не считаю что такое таскание соединения по всем слоям и методам оправдано. На моей практике объект соединения создается при открытии программы и потом его бедного по всей системе кидают, и только в некоторых редких отдельных случаях необходимо создать отдельное соединение, например в отдельном потоке. У Нильссона в книге вообще нигде не проглядывается работа с соединениями, кроме как в главе про ORM, из чего я прихожу к выводу что соединение он получает вызывая статический метод внутри DAL-методов. Открываю Фаулера [АКПП], внимательно листаю, по всей книге раскиданы вызовы типа DB.Connection и ConnectionManager.INSTANCE.getConnection() и только в некоторых местах где реально нужно отдельное соединение Фаулер его создает.
Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?
Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"
Второй вопрос по поводу отделения бизнес-логики от бизнес-классов (DTO? или я ошибаюсь в терминологии?). Допустим есть сущность "счет". Тогда при расслоении мы создаем класс Invoice с полями InvoiceID, InvoiceN, InvoiceDate, InvoiceAmount и т.д. Кстати в таком виде куда его относить ? к DAL или BLL? Далее в DAL мы создаем класс InvoiceAccessor, который будет например иметь метод GetInvoiceByID() и другие методы для непосредственной связи счетов с БД и фактически будет являться еще и фабрикой. Вопрос в том, а не включить ли в класс Invoice методы бизнес-логики? Например для отмены инвойса мы можем включить в этот класс метод CancelInvoice(). Но другой подход тут — отделить методы бизнес-логики от данных, оставить класс Invoice только с полями в покое, и создать класс InvoiceManager, который будет иметь статический метод CancelInvoice()?
Получается, что в первом варианте, когда пользователь нажал на кнопку отменить счет, будет вызываться примерно такой код:
private void btnCancelInvoice_Click(object sender, EventArgs e)
{
...
// Ничего кстати что я DAL-метод вызываю из UI ?
Invoice invoice = InvoiceAccessor.GetInvoiceByID(invoiceID);
if(invoice.CancelInvoice())
Presentation.ShowSuccess("Selected invoice has been successfully cancelled!");
...
}
Во втором варианте, код будет таким:
private void btnCancelInvoice_Click(object sender, EventArgs e)
{
...
if(InvoiceManager.CancelInvoice(invoiceID))
Presentation.ShowSuccess("Selected invoice has been successfully cancelled!");
...
}
Как правильнее и почему?
Вот так, на пока хватит, кратко не получилось.
Жду ответов, мнений и советов опытных людей.
Здравствуйте, MozgC, Вы писали:
MC>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?
Ни то и не другое, кури connection pooling. Сценарии, когда соединение надо держать открытым для разных вызовов, в реальных приложениях крайне редки.
MC>Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"
... MC>Как правильнее и почему?
Здравствуйте, MozgC, Вы писали:
MC>Вопрос 1. А-ля "Передача connection'а vs получение (не открытие) connection'а где нужно"
Самая замечательная стратегия это иметь абстрактную фабрику соединений и инжектить её (IoC, Dependency Injection) в классы доступа к данным (паттерн DAO).
В фабрике реализуется нужный набор фич
— пулироваине соединения
— валиадация соединений
— ассоциация соединений с пользовательской сессией (если надо)
— ассоциация соединения с бизнес-транзакцией \ бизнес-операцией (если надо)
MC>Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"
Уже верное поделились ссылкой выше. Неоднозначный и не простой вопрос.
MC>Получается, что в первом варианте, когда пользователь нажал на кнопку отменить счет, будет вызываться примерно такой код:
MC> // Ничего кстати что я DAL-метод вызываю из UI ?
Полный отстой. Где тут MVC, где тут отделение View/BL/DAL?
Здравствуйте, IB, Вы писали:
MC>>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства? IB>Ни то и не другое, кури connection pooling. Сценарии, когда соединение надо держать открытым для разных вызовов, в реальных приложениях крайне редки.
Т.е. благодаря Connection Pooling в DAL-методах я просто пишу типа:
Здравствуйте, MozgC, Вы писали: MC>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?
Ни то, ни другое — соединение вообще не должно входить за пределы уровня "модели".
А если ты какой-нибудь из бизнес-объектов решишь перенести в другую систему и он станет доступен только через web-сервис? Бужешь перепахивать весь код завязанный на соединение с БД?
MC>[b]Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности
Это связанные вопросы. Две стороны одной монеты:
— "уровень модели" не должен публиковать методы которые могут разрушить целостность конкретного бизнес-объекта или модели в целом;
— набор методов "модели" должен быть достаточен для выполнения операций высокоуровневой логики, и при этом минимален (классическая формулировка "необходимо и достаточно").
То есть, если некоторая операция требует прямого обращения к служебным данным или функциям (соединение с БД к ним относится), она должна быть обобщена (!) и реализована не уровне модели. Если же эта опреация выражается через другие опреации модели — то ей место на уровне сервиса.
Здравствуйте, MozgC, Вы писали:
B>>Типа того, только, ИМХО, статику всю нужно повыкидывать. В обоих методах GetSupplierInvoiceByID() и ConnectToDb() MC>Вот этот вопрос меня тоже интересует. Почему некоторые люди советуют избавляться от статических методов?
В статике сложно обобщать, использовать полиморфизм и вообще всякое из OOП. То есть на данный момент, она может быть вполне приемлема, но если закладыватся на серьезный рост и долговременное развитие проекта, то потом могут вылезти сложности. Чтобы сделать метод статическим нужно довольно веское обоснование, как например, ограничение метода от не статических полей класса, либо функциональность однозначно требующая статики.