目前我有:
class EntityFOO
{
EntityFOO LoadFromXml(XDocument) {...}
EntityFOO LoadFromDB(string) {...}
}
class EntityBAR
{
EntityBAR LoadFromXml(XDocument) {...}
EntityBAR LoadFromDB(string) {...}
}
我想重构并提取一个接口。我想要这样的东西:
abstract class Entity
{
static string DatabaseConnectionString = "shared_across_implementations";
abstract Entity LoadFromXml(XDocument);
abstract Entity LoadFromDB(string);
}
class EntityBAR : Entity
{
EntityBAR LoadFromXml(XDocument) {...}
EntityBAR LoadFromDB(string) {...}
}
请注意,Entity
的实现返回自己的类型EntityBAR
而不是父Entity
。假设我将不得不以某种方式使用<Generics>
。
像这样吗?
abstract class Entity<T> where T : Entity<T>
{
static string DatabaseConnectionString = "shared_across_implementations";
abstract T LoadFromXml(XDocument);
abstract T LoadFromDB(string);
}
class EntityBAR : Entity<EntityBAR>
{
EntityBAR LoadFromXml(XDocument) {...}
EntityBAR LoadFromDB(string) {...}
}
当然,未经测试,而且Entity<T> where T : Entity<T>
扰乱了我的直觉,让我认为这是某种奇怪的类型递归问题。 但我不认为这是一个问题。
虽然我更关心的是你在那里的那些LoadFrom...
方法。 如果这些是类型本身的工厂,它们不是static
吗? 这将改变任何类型的继承方案。 对我来说,需要一个实例来构建实例似乎很奇怪。
也许具有string
和XDocument
参数的构造函数对此更有意义? 由于构造函数没有返回类型,这将使问题变得毫无意义。 结构上像这样的东西(也是徒手的,未经测试的,有点伪代码(:
abstract class Entity
{
static string DatabaseConnectionString = "shared_across_implementations";
protected Entity(XDocument) {...}
protected Entity(string) {...}
}
class EntityBAR : Entity
{
public EntityBAR(XDocument) : base(XDocument) {...}
public EntityBAR(string) : base(string) {...}
}
当然,除非构建/初始化对象的操作非常繁重并且本身涉及其他依赖项。 在这种情况下,构造函数并不总是一个安全的地方,设计将调用单独的工厂对象。 这些可以基于实例并返回这些实例。
但是,在对象本身上具有基于实例的初始化步骤本质上意味着使用代码需要手动记住构建任何给定对象是一个两步过程。 这引入了潜在的错误和其他逻辑问题。