具有相同参数类型的构造函数
我有一个带有两个构造函数的Person对象,一个构造函数使用int(personId),另一个构造函数使用字符串(logonName)。我想要另一个采用字符串(badgeNumber)的构造函数。我知道无法做到这一点,但似乎是一种常见情况。有解决这个问题的优雅方法吗?我想这将适用于任何重载方法。代码:
public class Person { public Person() {} public Person(int personId) { this.Load(personId); } public Person(string logonName) { this.Load(logonName); } public Person(string badgeNumber) { //load logic here... }
...等等。
解决方案
回答
我们可能会考虑使用自定义类型。
例如,创建LogonName和BadgeNumber类。
然后函数声明看起来像...
public Person(LogonName ln) { this.Load(ln.ToString()); } public Person(BadgeNumber bn) { //load logic here... }
这样的解决方案可能为我们提供了一个很好的位置,可以保留控制这些字符串的格式和用法的业务逻辑。
回答
不。
我们可能会考虑一个标志字段(可读性枚举),然后让构造函数使用htat来确定意思。
回答
我唯一想处理我们想要做的事情就是必须使用params,一种描述参数类型(带有LogonName,BadgeNumer等的枚举),第二种是param值。
回答
那行不通。我们可能会考虑制作一个称为BadgeNumber的类,该类包装一个字符串,以避免这种歧义。
回答
我们也许可以改用工厂方法?
public static Person fromId(int id) { Person p = new Person(); p.Load(id); return p; } public static Person fromLogonName(string logonName) { Person p = new Person(); p.Load(logonName); return p; } public static Person fromBadgeNumber(string badgeNumber) { Person p = new Person(); // load logic return p; } private Person() {}
回答
我们不能有两个具有相同签名的不同构造函数/方法,否则,编译器将如何确定要运行的方法。
正如Zack所说,我会考虑创建一个"选项"类,在其中我们可以实际传递自定义类型中包含的参数。这意味着我们可以传递尽可能多的参数,并使用选项进行操作,只是要小心不要创建试图做所有事情的整体方法。
或者,或者投票支持工厂模式。
回答
我们可以使用静态工厂方法:
public static Person fromLogon(String logon) { return new Person(logon, null); } public static Person fromBadge(String badge) { return new Person(null, badge); }
回答
我们可以切换到工厂样式模式。
public class Person { private Person() {} public static PersonFromID(int personId) { Person p = new Person(). person.Load(personID); return p; this.Load(personId); } public static PersonFromID(string name) { Person p = new Person(). person.LoadFromName(name); return p; } ... }
或者,如建议的那样,使用自定义类型。我们也可以使用泛型来破解某些东西,但出于可读性考虑,我不建议我们这样做。
回答
正如已经建议的那样,在这种情况下,自定义类型是可行的方法。
回答
怎么样 ...
public Person(int personId) { this.Load(personId); } public Person(string logonName) { this.Load(logonName); } public Person(Object badgeNumber) { //load logic here... }
回答
我们可以想到四个选项,其中三个已经被其他人命名:
- 按照其他几个人的建议,走工厂路线。这样做的一个缺点是我们不能通过重载获得一致的命名(否则我们将遇到相同的问题),因此从表面上看不太干净。另一个较大的缺点是,它排除了直接在堆栈上分配的可能性。如果采用这种方法,则所有内容都将分配在堆上。
- 自定义对象包装器。这是一种很好的方法,如果我们是从头开始的话,我会建议我们这样做。如果我们有很多使用(例如)徽章作为字符串的代码,那么重写代码可能会使该选项不可行。
- 在方法中添加一个枚举,指定如何处理字符串。这可行,但是要求我们重写所有现有调用以包括新的枚举(尽管我们可以根据需要提供默认值以避免其中的某些情况)。
- 添加一个未使用的伪参数来区分两个重载。例如在方法上添加一个" bool"。标准库在几个地方都采用了这种方法,例如
std :: nothrow
是operator new
的伪参数。这种方法的缺点是丑陋且无法扩展。
如果我们已有大量的现有代码,建议我们添加枚举(可能具有默认值)或者添加哑参数。两者都不漂亮,但两者都很容易改装。
如果我们是从头开始或者仅有少量代码,则建议我们使用自定义对象包装器。
如果代码大量使用原始的badge
/logonName
字符串,但不大量使用Person
类,则可以使用factory方法。
回答
如果使用的是C3.0,则可以使用对象初始化程序:
public Person() { } public string Logon { get; set; } public string Badge { get; set; }
我们将这样调用构造函数:
var p1 = new Person { Logon = "Steve" }; var p2 = new Person { Badge = "123" };