C# 型铸造与工厂模式
我很难弄清楚如何在我试图创建的DTO映射器中实现工厂模式。我很确定我需要重新考虑我的设计。下面是一个非常小的例子,说明了我的想法:C# 型铸造与工厂模式,c#,factory-pattern,C#,Factory Pattern,我很难弄清楚如何在我试图创建的DTO映射器中实现工厂模式。我很确定我需要重新考虑我的设计。下面是一个非常小的例子,说明了我的想法: public abstract class Person { public string Name { get; set; } public decimal Salary { get; set; } } public class Employee : Person { public Employee() {
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";
我如何在不向飞行员输入飞行员号码的情况下加载飞行员号码??这样做是错误的吗?我可以把飞行员号码放在Person类中,但是Employee会继承这个号码,这不是我想要的。我能做什么
谢谢
-Jackson当对象在实现上不同时,最好使用工厂模式,而不是接口。在您的情况下,工厂模式不太有利,您最好直接创建对象(或者其他模式更好)。是否必须使用字符串来传递所需的类型?您可以使用泛型:
public static T CreatePerson<T>() where T : Person
public static T CreatePerson(),其中T:Person
现在很难说这是否会起作用,因为我们不知道你在CreatePerson中真正在做什么的细节。如果它只是调用一个无参数构造函数,这很简单:
public static T CreatePerson<T>() where T : Person, new()
{
return new T();
}
public static T CreatePerson(),其中T:Person,new()
{
返回新的T();
}
然而,这也是毫无意义的,因为调用方可以这样做。仿制药在你的实际情况下可行吗?如果没有,你能解释一下为什么没有,我们可以试着解决这个问题吗?解决这个问题没有简单的方法 要使用PilotNumber属性,您需要Pilot类型。使用工厂模式意味着你放弃了不同的子类型的人 如果有什么安慰的话BCL也有类似的模式
var req = WebRequest.CreateRequest("http://someUrl");
((HttpWebRequest)req).Contentlenght = ...;
您可以将特定类型的方法添加到PersonFactory类中,或者添加一个泛型的
CreatePerson()
方法,但这只有在调用方已经知道它应该接收什么类型的人时才有用。也许是这样,也许不是
在这种情况下,我希望实际调用PersonFactory.CreatePerson的代码不会知道或关心返回的是什么类型的人。如果在这一点之后您有一些代码已经知道或知道您拥有的person对象的类型,那么您只需将其强制转换
下面是一个代码示例,演示了在工厂和不同的使用场景中可以执行的操作,试图解释何时只需要强制转换或何时不需要强制转换
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<T>()
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<Pilot>()?
p = PersonFactory.CreatePilot();
p = PersonFactory.CreatePerson<Pilot>();
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
}
}
}
公共静态类PersonFactory
{
公共静态Person CreatePerson()
{
返回新人();
}
公共静态雇员CreateEmployee()
{
返回新员工();
}
公共静态导频CreatePilot()
{
返回新飞行员();
}
公共静态T CreatePerson()
式中T:人
{
返回(T)CreatePerson(类型(T));
}
公共静态人员CreatePerson(类型)
{
如果(类型==类型(人))
返回CreatePerson();
else if(类型==类型(员工))
返回CreateEmployee();
否则如果(类型==类型(飞行员))
返回CreatePilot();
其他的
抛出新ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture,“无法识别的类型[{0}]”,type.FullName),“类型”);
}
公共静态Person CreatePerson(字符串类型Person)
{
开关(个人类型)
{
案例“雇员”:
返回CreateEmployee();
“试点”案例:
返回CreatePilot();
违约:
返回CreateEmployee();
}
}
}
类UsageExample
{
Person GetPerson()
{
飞行员p;
p=(Pilot)PersonFactory.CreatePerson(“Pilot”);//这段代码已经知道需要一个Pilot,所以为什么不直接调用CreatePilot或CreatePerson()?
p=PersonFactory.CreatePilot();
p=PersonFactory.CreatePerson();
返回p;
}
Person GetPerson(类型personType)
{
Person p=PersonFactory.CreatePerson(personType);
//这段代码无法知道刚刚创建了什么类型的人,因为它取决于参数
返回p;
}
void KnowledgableCaller()
{
类型personType=类型(飞行员);
Person p=这个.GetPerson(typeof(Pilot));
//这段代码知道刚刚返回的Person对象应该是Pilot类型
飞行员飞行员=(飞行员)p;
//继续访问特定于飞行员的功能
}
void IgnorantCaller()
{
Person p=this.GetPerson();
//此调用方不知道刚刚返回的Person对象的类型
//但它可以进行测试来找出答案
先导=p为先导;
if(pilot!=null)
{
//继续访问特定于飞行员的功能
}
}
}
仅响应单词“DTO映射器”:泛型在这种情况下可能有效。我基本上有一个数据库表,每个类型层次结构有一个表。让我们假设一个带有“PersonType”字段的Person位置。和另一个包含“飞行员”特定信息的表格。要获得人员的结果集,if将遍历数据库行列表,如果是“Pilot”类型,则加载Pilot表信息,如果是“Employee”类型,则加载该特定信息。但是,不要将pilot内容加载到employee对象中……这会让它更清晰吗?谢谢!我喜欢IgnorantCaller方法。我可能可以使用它!我将从每个类型的表中加载一组记录,每个层次结构的表。如果此人的“PersonType”中有一个“pilot”'列,然后从先导表中加载先导编号。如果行在PersonType字段中有“Employee”类型,则不加载飞行员编号。。“马特·格里尔,你能再详细解释一下吗?”对象在实现上有所不同,而不是接口'-->这如何适用于这种情况?@Zortkun它之所以适用,是因为只有Pilot