Конструкторы с перегрузкой цепи? - PullRequest
3 голосов
/ 05 октября 2009

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

Я просмотрел пару учебников, чтобы найти «Лучшую практику» для этой функции, и, к сожалению, у меня не получилось.

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

Пример приложения № 1 использует то, что большинство книг говорят мне, что это «предпочтительный» способ, но большинство примеров, приведенных вместе с этими утверждениями, не соответствуют контексту моей ситуации. Я беспокоюсь, что поток не так удобен для чтения, как приложение № 2.

using System;

namespace TestApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var one = new OverloadedClassTester();
            var two = new OverloadedClassTester(42);
            var three = new OverloadedClassTester(69, "Mike", 24);

            Console.WriteLine("{0}{1}{2}", one, two, three);

            Console.ReadKey();
        }        
    }

    public class OverloadedClassTester
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int age { get; set; }

        public OverloadedClassTester() : this(0) { }

        public OverloadedClassTester (int _ID) : this (_ID, "", 0)
        {
            this.age = 14;  // Pretend that this was sourced from a database
            this.Name = "Steve"; // Pretend that this was sourced from a database
        }

        public OverloadedClassTester(int _ID, string _Name, int _age)
        {
            this.ID = _ID;
            this.Name = _Name;
            this.age = _age;
        }

        public override string ToString()
        {
            return String.Format("ID: {0}\nName: {1}\nAge: {2}\n\n", this.ID, this.Name, this.age);
        }
    }
}

Этот образец (приложение № 2) «выглядит» более читабельным - в этом, я думаю, легче увидеть ход операции. Однако это выглядит эффективным с точки зрения сохраненных символов: с. Кроме того, не опасно ли, что он вызывает метод объекта до его полной инициализации, или это не проблема?

using System;

namespace TestApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var one = new OverloadedClassTester();
            var two = new OverloadedClassTester(42);
            var three = new OverloadedClassTester(69, "Mike", 24);

            Console.WriteLine("{0}{1}{2}", one, two, three);

            Console.ReadKey();
        }        
    }

    public class OverloadedClassTester
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int age { get; set; }

        public OverloadedClassTester()
        {
            initialise(0, "", 21); // use defaults.
        }

        public OverloadedClassTester (int _ID)
        {
            var age = 14;  // Pretend that this was sourced from a database (from _ID)
            var Name = "Steve"; // Pretend that this was sourced from a database (from _ID)

            initialise(_ID, Name, age);
        }

        public OverloadedClassTester(int _ID, string _Name, int _age)
        {
            initialise(_ID, _Name, _age);
        }

        public void initialise(int _ID, string _Name, int _age)
        {
            this.ID = _ID;
            this.Name = _Name;
            this.age = _age;
        }

        public override string ToString()
        {
            return String.Format("ID: {0}\nName: {1}\nAge: {2}\n\n", this.ID, this.Name, this.age);
        }
    }
}

Каков «правильный» способ решения этой проблемы и почему?

Спасибо,

Ответы [ 5 ]

12 голосов
/ 05 октября 2009

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

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

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

2 голосов
/ 05 октября 2009

Не используйте вызовы базы данных в конструкторе. Это означает, что ваш конструктор делает много работы. См. http://misko.hevery.com/code-reviewers-guide/ (руководство Google по написанию тестируемого кода).

Кроме того, конструкторы цепочки (вариант 2) выглядят хорошо. Главным образом потому, что, как вы говорите, это читабельно. Но почему вы присваиваете this.Name и т.д. в конструкторе и делаете это снова при инициализации. Вы можете назначить все значения при инициализации.

1 голос
/ 05 октября 2009

Может как то так?

public class OverloadedClassTester
{
    public int Id { get; private set; }
    public string Name { get; private set; }
    public int Age { get; private set; }


    public OverloadedClassTester (Person person)
      : this (person.Id, person.Name, person.Age) { }

    public OverloadedClassTester(int id, string name, int age)
    {
        Id = id;
        Name = name;
        Age = age;
    }

    public override string ToString()
    {
        return String.Format("Id: {0}\nName: {1}\nAge: {2}\n\n", 
            Id, Name, Age);
    }
}
0 голосов
/ 05 октября 2009

Я предпочитаю №1, конструкторов цепочек, с точки зрения обслуживания. Когда кто-то позже вернется, чтобы отредактировать код, вы не захотите, чтобы он редактировал метод initialise () и не осознавал, что он вызывается из конструктора. Я думаю, что более интуитивно понятно иметь все функциональные части в конструкторе какого-то рода.

Лично я все время использую конструкторские цепочки.

0 голосов
/ 05 октября 2009

может быть, было бы лучше использовать дополнительные параметры? В этом случае вы должны создать один конструктор и инициализировать значения параметрами, которые вы хотите установить.

Дополнительная информация: текст ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...