Если .Create () не может создать экземпляр, должен ли он вернуть пустой объект, нуль или вызвать исключение? - PullRequest
3 голосов
/ 10 июня 2009

Я хочу иметь возможность создавать экземпляры любого объекта в моем приложении с таким кодом:

SmartForm smartForm = SmartForm.Create("id = 23");
Customer customer = Customer.Create("id = 222");

Сейчас я обсуждаю, что Create () должен вернуть, если этот объект не существует.

  • если Create () возвращает пустой объект , то это своего рода «нулевой шаблон», и я все еще могу передавать этот объект вокруг моего приложения и вызывать методы для него, что делает программирование с этой моделью удобно и просто

  • если Create () возвращает null , то мне нужно после каждого экземпляра проверять, равен объект нулю или нет, что делает программирование немного более утомительным, но более явным. Проблема в том, что если вы забудете проверить нулевое значение, ваше приложение может работать долгое время, не зная, что вы не проверяете нулевое значение, а затем внезапно прекратит работу

  • если Create () выдает исключение , это в основном то же самое, что и возвращение нулевого значения, но делает программирование еще более утомительным, заставляя вас создавать блок try, next, finally для каждого экземпляра, но вы можете выдавать различные типы исключений (которые вы не можете использовать с нулевым решением), которые могут пузыриться, чтобы вы могли более явно обрабатывать глубокие ошибки в вашем пользовательском интерфейсе, так что это, я думаю, самое надежное решение, хотя и приведет к попытке / поймать код наворот

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestFactory234.Models
{
    public class SmartForm : Item
    {
        public string IdCode { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int LabelWidth { get; set; }

        public SmartForm() { }

        private SmartForm(string loadCode)
        {
            _loadCode = loadCode;
            TryToInstantiateFromDatabase();
        }

        public static SmartForm Create(string loadCode)
        {
            SmartForm smartForm = new SmartForm(loadCode);

            if (!smartForm.IsEmpty())
            {
                return smartForm;
            }
            else
            {
                return null;
            }
        }
    }
}

Ответы [ 6 ]

6 голосов
/ 10 июня 2009

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

Звучит как правильное время для использования ArgumentException, ИМО.

Если вы обнаружите, что создаете «раздувание» try / catch, посмотрите, почему вам действительно нужно перехватывать исключения, а не просто позволять им всплывать.

2 голосов
/ 10 июня 2009

Если поведение по умолчанию - создание экземпляра, исключительное поведение - сбой при создании -> Исключение

Что бы вы сделали с пустым объектом? Вы говорите, что все еще можете это передать - имеет ли это смысл? Что делают методы, когда вы их вызываете?

Возможно, вам следует реализовать второй TryCreate () метод.

Я бы реализовал Exception-вариант, но это зависит от поведения, которое вам нужно.

2 голосов
/ 10 июня 2009

Если он возвращает пустой объект, то вы продолжите предполагать, что он действителен - или вам придется выполнить какой-то сложный тест, чтобы увидеть, пустой он или нет. Если он возвращает нулевое значение, вам всегда нужно проверять нулевое значение (и, возможно, это нормально). Я бы предпочел, чтобы он вызывал исключение - предполагая, что ваш код разработан так, чтобы этого не происходило. Если это нормальный сценарий, тогда ноль может быть лучшим выбором.

1 голос
/ 10 июня 2009

В вашем примере кода вызывается метод try load from DB, и соглашение Create выглядит очень похоже на объект Castle ActiveRecord . Почему бы не разделить операцию «Получить / Создать базу данных», позволить инфраструктуре выполнять работу и полагаться на их соглашения?

[ActiveRecord("Forms")]
public class SmartForm : Item
{
    [PrimaryKey("Id")]
    public string IdCode { get; set; }
    [Property]
    public string Title { get; set; }
    [Property]
    public string Description { get; set; }
    [Property]
    public int LabelWidth { get; set; }
}

Вы получаете / создаете подобные экземпляры

SmartForm entity = ActiveRecordMediator<SmartForm>.Find(1);
SmartForm otherEntity = ActiveRecordMediator<SmartForm>.FindFirst(/* criteria */);

Существует множество других методов поиска экземпляров. Я думаю, вы обнаружите, что значения по умолчанию ActiveRecord относительно выброса исключений , возврата нуля или, в случае коллекций, пустой коллекции , очень последовательны и хорошо реализованы.

0 голосов
/ 22 марта 2011

Если можно предвидеть, что создание может завершиться неудачей, но большая часть кода приложения ожидает, что оно будет работать, вам действительно следует реализовать две версии метода создания, одна из которых должна либо завершиться успешно, либо выдать исключение, и другой из которых должен указывать на ожидаемые сбои с помощью других средств, кроме генерации исключения и генерирования исключения только для сбоев, которые вызывающий, вероятно, не ожидает (например, CpuIsOnFireException). Обычный шаблон для этого - метод TryCreate, возвращающий логическое значение, указывающее успех, сохраняющий созданный аргумент в аргумент by-ref. Мне не очень нравится этот шаблон, так как он не предоставляет никаких средств для обозначения чего-либо, кроме статуса «сбой при прохождении» (т.е. ничего о том, почему он не прошел). Я думаю, что было бы лучше иметь функцию try, возвращающую либо новое, либо значение null, но иметь аргумент by-ref, указывающий причину сбоя. Обратите внимание, что этот подход позволит лучше использовать неявную типизацию (например, ключевое слово «var» в C #).

0 голосов
/ 10 июня 2009

Если вы создаете фабрику форм, вам лучше передать перечисление, а не строку (если, конечно, это не представляет собой архитектуру подключаемого модуля).

...