2009-10-05 2 views
3

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

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

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

Образец приложения № 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) «появляется» более читабельным - в том, что я думаю, что это легче увидеть поток работы. Однако он действительно эффективен с точки зрения сохраненных символов: p. Кроме того, разве не опасно, что он вызывает метод объекта до его полной инициализации или это не проблема?

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); 
     } 
    } 
} 

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

Спасибо,

+0

«Притворись, что это было из базы данных» - этот комментарий немного сбивает с толку. Означает ли это, что вы будете обращаться к базе данных только в конструкторе * that * и в противном случае использовать параметры? Я считаю это очень запутанным. – Groo

ответ

12

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

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

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

+0

Лично я предпочитаю решение # 1. Моя главная проблема связана с тем фактом, что назначение переменной происходит ретроспективно для вызова «самого большого» конструктора. Сначала это показалось мне немного разрозненным, но я полагаю, что могу привести это к кривой обучения? :) – Mike

+0

Я не уверен, что я понимаю, что вы имеете в виду во втором предложении ... если бы вы могли уточнить, я объясню :) –

+0

Должно быть, было слишком много кофе вчера, извините! [В приложении №1] Если мы возьмем строку: «var two = new OverloadedClassTester (42);» Я понимаю, что он сначала сделает объект со значениями [id: 42], [name: ""] & [age: 0]. После этого она возрастет до «14» и назовет «Стив». Сначала я подумал, что это немного неудобно, но, адаптировав это решение к тому, что я действительно намереваюсь сделать с этим, этот формат является довольно хорошим способом предоставления «значений по умолчанию». :) – Mike

0

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

Дополнительная информация: link text

+1

Возможно, когда выпущена версия 4.0 этого языка? –

+0

Да, я играл в arround с 4.0 .NET - это действительно хорошо. – brokenisfixed

2

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

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

0

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

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

1

Возможно, что-то вроде этого?

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); 
    } 
}