Если я хочу сохранить и извлечь объект, должен ли я создать другой класс для его обработки или лучше сделать это в самом классе? Или, может быть, смешивая оба?
Что рекомендуется в соответствии с парадигмой ООД?
Например
Class Student
{
public string Name {set; get;}
....
public bool Save()
{
SqlConnection con = ...
// Save the class in the db
}
public bool Retrieve()
{
// search the db for the student and fill the attributes
}
public List<Student> RetrieveAllStudents()
{
// this is such a method I have most problem with it
// that an object returns an array of objects of its own class!
}
}
Против. (Я знаю, что рекомендуется следующее, однако мне кажется, что это немного против сплоченности Student
класса)
Class Student { /* */ }
Class DB {
public bool AddStudent(Student s)
{
}
public Student RetrieveStudent(Criteria)
{
}
public List<Student> RetrieveAllStudents()
{
}
}
Как насчет их смешивания?
Class Student
{
public string Name {set; get;}
....
public bool Save()
{
/// do some business logic!
db.AddStudent(this);
}
public bool Retrieve()
{
// build the criteria
db.RetrieveStudent(criteria);
// fill the attributes
}
}
design
object-oriented
Ahmad
источник
источник
Ответы:
Принцип единой ответственности , разделение интересов и функциональная сплоченность . Если вы прочитаете эти концепции, вы получите ответ: разделите их .
Простая причина отделить
Student
класс от «DB» (илиStudentRepository
, чтобы следовать более популярным соглашениям), состоит в том, чтобы позволить вам изменить свои «бизнес-правила», присутствующие вStudent
классе, не затрагивая код, отвечающий за постоянство, и наоборот.Этот вид разделения очень важен не только между бизнес-правилами и постоянством, но и между многими проблемами вашей системы, чтобы позволить вам вносить изменения с минимальным воздействием в несвязанных модулях (минимально, потому что иногда это неизбежно). Это помогает создавать более надежные системы, которые легче поддерживать и которые более надежны при постоянных изменениях.
Смешивая бизнес-правила и постоянство, либо с одним классом, как в первом примере, либо с
DB
зависимостьюStudent
, вы связываете две совершенно разные задачи. Может показаться, что они принадлежат друг другу; они кажутся связными, потому что используют одни и те же данные. Но вот в чем дело: сплоченность не может быть измерена только данными, которые разделяются между процедурами, вы также должны учитывать уровень абстракции, на котором они существуют. Фактически, идеальный тип сцепления описывается как:И,
Student
конечно же , выполнение проверок на некоторое время и их сохранение не образуют «единой четко определенной задачи». Итак, опять же, бизнес-правила и механизмы персистентности - это два совершенно разных аспекта системы, которые по многим принципам хорошего объектно-ориентированного проектирования должны быть разделены.Я рекомендую прочитать о Чистой архитектуре , посмотреть этот доклад о Принципе единой ответственности (где используется очень похожий пример), а также посмотреть этот доклад о Чистой архитектуре . Эти понятия обрисовывают в общих чертах причины такого разделения.
источник
Student
класс должен быть правильно инкапсулирован, да? Как тогда внешний класс может управлять сохранением частного государства? Инкапсуляция должна быть сбалансирована с SoC и SRP, но простой выбор одного из двух без тщательного взвешивания компромиссов, вероятно, ошибочен. Возможное решение этой загадки - использование частных средств доступа к пакетам для использования кода персистентности.Оба подхода нарушают принцип единой ответственности. Первая версия дает
Student
классу множество обязанностей и связывает его с определенной технологией доступа к БД. Второе приводит к огромномуDB
классу, который будет отвечать не только за студентов, но и за любой другой тип объекта данных в вашей программе. РЕДАКТИРОВАТЬ: ваш третий подход является худшим, поскольку он создает циклическую зависимость между классом DB иStudent
классом.Поэтому, если вы не собираетесь писать игрушечную программу, не используйте ни одну из них. Вместо этого используйте другой класс, такой как a,
StudentRepository
для предоставления API для загрузки и сохранения, предполагая, что вы собираетесь реализовать код CRUD самостоятельно. Вы также можете подумать об использовании платформы ORM , которая может выполнить тяжелую работу за вас (и среда обычно обеспечивает выполнение некоторых решений, в которых должны быть размещены операции загрузки и сохранения).источник
Существует довольно много шаблонов, которые можно использовать для сохранения данных. Есть шаблон « Единица работы» , есть шаблон « Репозиторий» , есть несколько дополнительных шаблонов, которые можно использовать, например, «Удаленный фасад» и т. Д. И т. Д.
У большинства из них есть поклонники и критики. Часто приходится выбирать то, что кажется наиболее подходящим для приложения, и придерживаться его (со всеми его плюсами и минусами, то есть не использовать оба шаблона одновременно ... если вы действительно не уверены в этом).
Как примечание: в вашем примере RetrieveStudent, AddStudent должен быть статическим методом (потому что они не зависят от экземпляра).
Еще один способ использования методов сохранения / загрузки в классе:
Лично я бы использовал такой подход только в довольно небольших приложениях, возможно, в инструментах для личного использования или где я могу с уверенностью предсказать, что у меня не будет более сложных вариантов использования, чем просто сохранение или загрузка объектов.
Также лично см. Шаблон «Единица работы». Когда вы узнаете это, это действительно хорошо как в небольших, так и в больших случаях. И это поддерживается множеством фреймворков / apis, например, EntityFramework или RavenDB.
источник
Если это очень простое приложение, в котором объект более или менее привязан к хранилищу данных и наоборот (т.е. его можно рассматривать как свойство хранилища данных), то может иметь смысл иметь метод .save () для этого класса.
Но я думаю, что это было бы довольно исключительным.
Скорее, обычно лучше позволить классу управлять своими данными и своей функциональностью (например, хорошим гражданином ОО) и перенести механизм персистентности в другой класс или набор классов.
Другой вариант - использовать постоянную среду, которая определяет постоянство декларативно (как в случае с аннотациями), но все же выводит сохранение из памяти.
источник
Что касается
RetrieveAllStudents()
метода, вы чувствуете, что он прав, он действительно неуместен, потому что у вас может быть несколько разных списков студентов. Почему бы просто не сохранить список (ы) внеStudent
класса?источник