我有一个基类来处理"工作".工厂方法根据作业类型创建派生的"作业处理程序"对象,并确保使用所有作业信息初始化作业处理程序对象.
调用工厂方法为Job和Person分配请求处理程序:
public enum Job { Clean, Cook, CookChicken }; // List of jobs.
static void Main(string[] args)
{
HandlerBase handler;
handler = HandlerBase.CreateJobHandler(Job.Cook, "Bob");
handler.DoJob();
handler = HandlerBase.CreateJobHandler(Job.Clean, "Alice");
handler.DoJob();
handler = HandlerBase.CreateJobHandler(Job.CookChicken, "Sue");
handler.DoJob();
}
Run Code Online (Sandbox Code Playgroud)
结果:
Bob is cooking.
Alice is cleaning.
Sue is cooking.
Sue is cooking chicken.
Run Code Online (Sandbox Code Playgroud)
工作处理程序类:
public class CleanHandler : HandlerBase
{
protected CleanHandler(HandlerBase handler) : base(handler) { }
public override void DoJob()
{
Console.WriteLine("{0} is cleaning.", Person);
}
}
public class CookHandler : HandlerBase
{
protected CookHandler(HandlerBase handler) : base(handler) { }
public override void DoJob()
{
Console.WriteLine("{0} is cooking.", Person);
}
}
Run Code Online (Sandbox Code Playgroud)
子级作业处理程序:
public class CookChickenHandler : CookHandler
{
protected CookChickenHandler(HandlerBase handler) : base(handler) { }
public override void DoJob()
{
base.DoJob();
Console.WriteLine("{0} is cooking chicken.", Person);
}
}
Run Code Online (Sandbox Code Playgroud)
最好的做事方式?我一直在努力解决这些问题:
HandlerBase基类:Dictionary<Job,Type>地图乔布斯处理程序类.看一下基类:
public class HandlerBase
{
// Dictionary maps Job to proper HandlerBase type.
private static Dictionary<Job, Type> registeredHandlers =
new Dictionary<Job, Type>() {
{ Job.Clean, typeof(CleanHandler) },
{ Job.Cook, typeof(CookHandler) },
{ Job.CookChicken, typeof(CookChickenHandler) }
};
// Person assigned to job. PRIVATE setter only accessible to factory method.
public string Person { get; private set; }
// PRIVATE constructor for data initialization only accessible to factory method.
private HandlerBase(string name) { this.Person = name; }
// Non-private "copy constructor" REQUIRES an initialized base object.
// Only the factory method can make a HandlerBase object.
protected HandlerBase(HandlerBase handler)
{
// Prevent creating new objects from non-base objects.
if (handler.GetType() != typeof(HandlerBase))
throw new ArgumentException("THAT'S ILLEGAL, PAL!");
this.Person = handler.Person; // peform "copy"
}
// FACTORY METHOD.
public static HandlerBase CreateJobHandler(Job job, string name)
{
// Look up job handler in dictionary.
Type handlerType = registeredHandlers[job];
// Create "seed" base object to enable calling derived constructor.
HandlerBase seed = new HandlerBase(name);
object[] args = new object[] { seed };
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
HandlerBase newInstance = (HandlerBase)Activator
.CreateInstance(handlerType, flags, null, args, null);
return newInstance;
}
public virtual void DoJob() { throw new NotImplementedException(); }
}
Run Code Online (Sandbox Code Playgroud)
看看工厂方法:
因为我已经在没有实例化的基础对象的情况下公开构造新对象,所以工厂方法首先将HandlerBase实例构造为用于调用所需派生类"复制构造函数"的"种子".
工厂方法用于Activator.CreateInstance()实例化新对象.Activator.CreateInstance()查找与请求的签名匹配的构造函数:
DerivedHandler(HandlerBase handler)因此,所需的构造函数是
HandlerBase对象被放入object[] args.BindingFlags.Instance,BindingFlags.NonPublic以便CreateInstance()搜索非公共构造函数(添加BindingFlags.Public以查找公共构造函数).实现接口或类时,不会强制使用构造函数.派生类中的构造函数代码是必需的:
protected DerivedJobHandler(HandlerBase handler) : base(handler) { }
Run Code Online (Sandbox Code Playgroud)
然而,如果遗漏构造函数,则不会得到一个友好的编译器错误,告诉您所需的确切方法签名:"'DerivedJobHandler'不包含带0参数的构造函数".
也可以编写一个消除任何编译器错误的构造函数,而不是WORSE! - 导致运行时错误:
protected DerivedJobHandler() : base(null) { }
Run Code Online (Sandbox Code Playgroud)
我不喜欢在派生类实现中没有强制执行必需构造函数的方法.
我在 HandlerBase 中看到了三个职责,如果它们相互解耦,可能会简化设计问题。
重新组织的一种方法是将 #1 和 #2 放在工厂类上,将 #3 放在具有内部构造函数的类上,以便只有工厂类可以根据您的内部要求调用它。您可以直接传入 Person 和 Job 值,而不是让构造函数从不同的 HandlerBase 实例中提取它们,这将使代码更易于理解。
一旦这些职责被分离,您就可以更轻松地独立发展它们。