键入Casting和Factory模式

我正在努力弄清楚如何在我试图创建的DTO映射器中实现工厂模式。 我很确定我需要重新考虑我的设计。 这是我正在运行的一个非常小的例子:

public abstract class Person { public string Name { get; set; } public decimal Salary { get; set; } } public class Employee : Person { public Employee() { this.Salary = 20000; } } public class Pilot : Person { public string PilotNumber { get; set; } public Pilot() { this.Salary = 50000; } } public static class PersonFactory { public static Person CreatePerson(string typeOfPerson) { switch (typeOfPerson) { case "Employee": return new Employee(); case "Pilot": return new Pilot(); default: return new Employee(); } } } 

并使用工厂:

 Person thePilot = PersonFactory.CreatePerson("Pilot"); ((Pilot)thePilot).PilotNumber = "123ABC"; 

如何在没有将其转发到Pilot的情况下到处加载试用号码? 这是错误的方法吗? 我可以将导频号放在Person类中,但是Employee将inheritance该号码,这不是我想要的。 我能做什么?

谢谢!

-Jackson

您可以将特定类型的方法添加到PersonFactory类,或者添加一个通用的CreatePerson()方法,但这只有在调用者已经知道它应该接收什么类型的人时才有用。 也许是这种情况,也可能不是。

在这种情况下,我希望实际调用PersonFactory.CreatePerson的代码不会知道或关心返回什么样的人。 如果您在该点之后有一些已经知道或确定您拥有的人物对象类型的代码,那么您只需要进行投射。

下面是一个代码示例,说明了您可以在工厂中执行的操作以及不同的使用方案,尝试解释何时需要进行强制转换或何时不进行强制转换。

 public static class PersonFactory { public static Person CreatePerson() { return new Person(); } public static Employee CreateEmployee() { return new Employee(); } public static Pilot CreatePilot() { return new Pilot(); } public static T CreatePerson() where T : Person { return (T)CreatePerson(typeof(T)); } public static Person CreatePerson(Type type) { if (type == typeof(Person)) return CreatePerson(); else if (type == typeof(Employee)) return CreateEmployee(); else if (type == typeof(Pilot)) return CreatePilot(); else throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, "Unrecognized type [{0}]", type.FullName), "type"); } public static Person CreatePerson(string typeOfPerson) { switch (typeOfPerson) { case "Employee": return CreateEmployee(); case "Pilot": return CreatePilot(); default: return CreateEmployee(); } } } class UsageExample { Person GetPerson() { Pilot p; p = (Pilot)PersonFactory.CreatePerson("Pilot"); // this code already knows to expect a Pilot, so why not just call CreatePilot or CreatePerson()? p = PersonFactory.CreatePilot(); p = PersonFactory.CreatePerson(); return p; } Person GetPerson(Type personType) { Person p = PersonFactory.CreatePerson(personType); // this code can't know what type of person was just created, because it depends on the parameter return p; } void KnowledgableCaller() { Type personType = typeof(Pilot); Person p = this.GetPerson(typeof(Pilot)); // this code knows that the Person object just returned should be of type Pilot Pilot pilot = (Pilot)p; // proceed with accessing Pilot-specific functionality } void IgnorantCaller() { Person p = this.GetPerson(); // this caller doesn't know what type of Person object was just returned // but it can perform tests to figure it out Pilot pilot = p as Pilot; if (pilot != null) { // proceed with accessing Pilot-specific functionality } } } 

当对象的实现不同而不是接口时,最好使用工厂模式。 在您的情况下,工厂模式不是太有用,您最好直接创建对象(或者其他一些模式可能更好)。

是否必须使用字符串来传达您想要的类型? 您可以使用generics来代替:

 public static T CreatePerson() where T : Person 

现在很难确切地说这是否有效,因为我们不知道你在CreatePerson中真正做了什么的细节。 如果它只是调用无参数构造函数,那很容易:

 public static T CreatePerson() where T : Person, new() { return new T(); } 

然而,这也是毫无意义的,因为呼叫者可以这样做。 仿制药在您的实际情况下是否可行? 如果没有,你能解释为什么不,我们可以尝试解决它吗?

没有简单的方法可以解决这个问题。

要使用PilotNumber属性,您需要Pilot类型。 使用工厂模式意味着您放弃了不同的Person子类型。

如果有任何安慰,BCL有类似的模式,

  var req = WebRequest.CreateRequest("http://someUrl"); ((HttpWebRequest)req).Contentlenght = ...;