У нас есть слой данных, который оборачивает Linq To SQL. В этом слое данных у нас есть этот метод (упрощенный)
int InsertReport(Report report)
{
db.Reports.InsertOnSubmit(report);
db.SubmitChanges();
return report.ID;
}
При отправке изменений идентификатор отчета обновляется значением в базе данных, которое мы затем возвращаем.
С вызывающей стороны это выглядит так (упрощенно)
var report = new Report();
DataLayer.InsertReport(report);
// Do something with report.ID
Глядя на код, ID был установлен внутри функции InsertReport как своего рода побочный эффект, и затем мы игнорируем возвращаемое значение.
Мой вопрос, должен ли я положиться на побочный эффект и сделать что-то подобное вместо этого.
void InsertReport(Report report)
{
db.Reports.InsertOnSubmit(report);
db.SubmitChanges();
}
или мы должны предотвратить это
int InsertReport(Report report)
{
var newReport = report.Clone();
db.Reports.InsertOnSubmit(newReport);
db.SubmitChanges();
return newReport.ID;
}
может быть даже
Report InsertReport(Report report)
{
var newReport = report.Clone();
db.Reports.InsertOnSubmit(newReport);
db.SubmitChanges();
return newReport;
}
Этот вопрос был поднят, когда мы создали модульный тест и обнаружили, что на самом деле не совсем ясно, что свойство идентификатора параметров отчета обновляется и что для имитации поведения, связанного с побочными эффектами, было неправильно, если хотите, пахнет кодом.
источник
Ответы:
Да, все нормально, и довольно часто. Это может быть неочевидным, как вы обнаружили.
В общем, я склонен иметь методы типа постоянства, возвращающие обновленный экземпляр объекта. То есть:
Да, вы возвращаете тот же объект, что и переданный, но это делает API более понятным. Нет необходимости в клоне - если что-то вызовет путаницу, если, как в исходном коде, вызывающая сторона продолжает использовать переданный объект.
Другой вариант - использовать DTO
Таким образом, API очень очевиден, и вызывающая сторона не может случайно попытаться использовать переданный / модифицированный объект. В зависимости от того, что делает ваш код, это может быть немного болезненно.
источник
IMO, это редкий случай, когда побочный эффект изменения желателен - поскольку у вашей сущности Report есть идентификатор, который, как можно предположить, уже имеет отношение к DTO, и, возможно, существует обязанность ORM гарантировать, что отчет в памяти сущность синхронизируется с объектом представления базы данных.
источник
Проблема в том, что без документации вообще не ясно, что делает метод и особенно почему он возвращает целое число.
Самым простым решением было бы использовать другое имя для вашего метода. Что-то вроде:
Тем не менее, это не является достаточно однозначным: если, как и в C #, экземпляр
report
объекта передается по ссылке, было бы трудно узнать,report
был ли изменен исходный объект, или если метод клонировал его и изменил только клон. Если вы решили изменить исходный объект, было бы лучше назвать метод:Более сложное (и, возможно, менее оптимальное) решение заключается в серьезном рефакторинге кода. Как насчет:
источник
Обычно программисты ожидают, что только методы экземпляра объекта могут изменить его состояние. Другими словами, я не удивляюсь, если
report.insert()
изменится идентификатор отчета, и это легко проверить. Нелегко задаться вопросом для каждого метода во всем приложении, изменяет ли он идентификатор отчета или нет.Я также утверждаю, что, возможно,
ID
вообще не должен принадлежатьReport
. Поскольку он не содержит действительного идентификатора так долго, у вас действительно есть два разных объекта до и после вставки, с разным поведением. Объект «before» может быть вставлен, но его нельзя извлечь, обновить или удалить. Объект «после» - полная противоположность. У одного есть идентификатор, а у другого нет. Способ их отображения может быть различным. Списки, в которых они появляются, могут быть разными. Связанные пользовательские разрешения могут быть разными. Они оба являются «отчетами» в английском смысле этого слова, но они очень разные.С другой стороны, ваш код может быть достаточно простым, чтобы одного объекта было достаточно, но это то, что нужно учитывать, если ваш код приправлен
if (validId) {...} else {...}
.источник
Нет, это не хорошо! Подходит для процедуры изменения параметра только в процедурных языках, где нет другого пути; в языках ООП вызывайте метод изменения объекта, в данном случае - отчета (что-то вроде report.generateNewId ()).
В этом случае ваш метод делает 2 вещи, следовательно, нарушает SRP: он вставляет запись в БД и генерирует новый идентификатор. Вызывающая сторона не может знать, что ваш метод также генерирует новый идентификатор, так как он просто называется insertRecord ().
источник
db.Reports.InsertOnSubmit(report)
метод change объекта?