我有一个处理“工作”的基类。工厂方法根据作业类型创建派生的“作业处理程序”对象,并确保使用所有作业信息初始化作业处理程序对象。
调用工厂方法来请求分配的作业和人员的处理程序:
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();
}
结果:
Bob is cooking.
Alice is cleaning.
Sue is cooking.
Sue is cooking chicken.
作业处理程序类:
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);
}
}
子类作业处理程序:
public class CookChickenHandler : CookHandler
{
protected CookChickenHandler(HandlerBase handler) : base(handler) { }
public override void DoJob()
{
base.DoJob();
Console.WriteLine("{0} is cooking chicken.", Person);
}
}
最好的做事方式?我一直在努力解决这些问题:
- 确保所有派生对象都有一个完全初始化的基础对象(指定的 Person)。
- 除了通过执行所有初始化的工厂方法之外,防止任何对象的实例化。
- 防止基类对象的实例化。
作业处理程序HandlerBase
基类:
- A
Dictionary<Job,Type>
将作业映射到处理程序类。
- 作业数据(即人员)的 PRIVATE setter 阻止访问,除非通过工厂方法。
- 除了工厂方法之外,没有默认构造函数和 PRIVATE 构造函数会阻止构造。
- 受保护的“复制构造函数”是唯一的非私有构造函数。必须有一个实例化的 HandlerBase 才能创建新对象,并且只有基类工厂才能创建基 HandlerBase 对象。如果尝试从非基对象创建新对象,“复制构造函数”将引发异常(同样,除了通过工厂方法之外,还会阻止构造)。
看一下基类:
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(); }
}
看一下工厂方法:
因为我已经在没有实例化基础对象的情况下不可能公开构造新对象,所以工厂方法首先构造一个HandlerBase
实例作为“种子”,用于调用所需的派生类“复制构造函数”。
工厂方法使用Activator.CreateInstance()
实例化新对象。 Activator.CreateInstance() 查找与请求的签名匹配的构造函数:
所需的构造函数是DerivedHandler(HandlerBase handler)
, thus,
- 我的“种子”
HandlerBase
物体被放置在object[] args
.
- 我结合
BindingFlags.Instance
and BindingFlags.NonPublic
以便 CreateInstance() 搜索非公共构造函数(添加BindingFlags.Public
找到一个公共构造函数)。
- Activator.CreateInstance() 实例化返回的新对象。
我不喜欢什么...
实现接口或类时不强制使用构造函数。派生类中的构造函数代码是强制性的:
protected DerivedJobHandler(HandlerBase handler) : base(handler) { }
然而,如果省略构造函数,您不会收到友好的编译器错误,告诉您所需的确切方法签名:“'DerivedJobHandler' 不包含采用 0 个参数的构造函数”。
也可以编写一个构造函数来消除任何编译器错误,而不是——更糟糕!——导致运行时错误:
protected DerivedJobHandler() : base(null) { }
我不喜欢没有办法在派生类实现中强制执行必需的构造函数。