我正在尝试构建一个类,它将通过传入对数据库中的记录的引用来启动它自己(意图是对数据库运行查询并且对象属性的返回值将会在其中设置),或通过“手动”指定值 - 这不需要数据库调用。
我看了几本教科书,发现了这项功能的“最佳实践”,遗憾的是我已经做错了。
我写了几个示例控制台应用程序,反映了我认为最可能的两个解决方案,但我不知道哪个是最好的正确实现?
示例应用程序#1使用了大多数书籍告诉我的“首选”方式,但大多数示例与这些声明并不符合我的情况。我在这里担心流程不如App#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);
}
}
}
此示例(App#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 :(得分:12)
我肯定会链接构造函数,因此只有一个才能完成“实际工作”。这意味着你只需要在一个地方做真正的工作,所以如果这项工作发生了变化(例如你需要在构造函数的末尾调用一些验证方法),你只需要一个你需要的地方改变代码。
使用更多参数进行“简单”重载调用重载是一种非常常见的模式IME。我发现它比第二个版本的更多可读,因为您可以轻松地告诉调用一个重载与使用默认值调用“更大”的重载相同。对于第二个版本,您必须比较构造函数的主体。
我尽量不要有多个构造函数尽可能直接链接到基类 - 除非它链接到不同的基类构造函数,当然(通常情况下除外)。
答案 1 :(得分:2)
不要在构造函数中使用数据库调用。这意味着你的构造函数正在做很多工作。请参阅http://misko.hevery.com/code-reviewers-guide/(编写可测试代码的Google指南)。
除此之外,链接构造函数(选项2)看起来很好。主要是因为你说它是可读的。但是为什么要在构造函数中分配this.Name等并在初始化中再次执行它。您可以在初始化中分配所有值。
答案 2 :(得分: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);
}
}
答案 3 :(得分:0)
也许最好使用可选参数?在这种情况下,您将创建一个构造函数并将值初始化为您要设置的参数。
更多信息:link text
答案 4 :(得分:0)
从维护的角度来看,我更喜欢链接构造函数#1。当有人回来编辑代码时,您不希望他们编辑initialise()方法,也不会意识到它是从构造函数中调用的。我认为在某种构造函数中包含所有功能部件更为直观。
就个人而言,我一直使用构造函数链接。