我的目标是编写一个抽象基类,其中包含一个派生“子实例”的方法。在这种方法中,已经完成了一些在所有派生类中都很常见的计算。
难点在于基类无法自己创建子类。所以我在我的基类中引入了一个类型参数T
和一个protected abstract
方法,该方法将返回T
的实例。
public abstract class Base<T> where T : Base<T>
{
public T GetChild()
{
string param = ComplexComputation();
return NewInstanceFrom(param);
}
protected abstract T NewInstanceFrom(string param);
}
// --- somewhere else: ---
public class Derivative : Base<Derivative>
{
public Derivative() { }
protected sealed override Derivative NewInstanceFrom(string param)
{
return new Derivative(param);
}
private Derivative(string param)
{
// some configuration
}
}
这种方法的缺点是我无法确保NewInstanceFrom
仅由基类调用。它也可以由继承自Derivative
的类调用。这就是我想要避免的。
所以我可以将功能封装在私有类或委托中:
public abstract class Base<T> where T : Base<T>
{
public T GetChild()
{
string param = ComplexComputation();
return subElementDerivator(param);
}
protected Base<T>(Func<string, T> subElementDerivator)
{
this.subElementDerivator = subElementDerivator;
}
private Func<string, T> subElementDerivator;
}
// --- somewhere else: ---
public class Derivative : Base<Derivative>
{
public Derivative()
: base(deriveSubElement)
{
}
private Derivative(string param)
: base(deriveSubElement)
{
// some configuration
}
private static Derivative deriveSubElement(string param)
{
return new Derivative(param);
}
}
但这引入了一个新对象。
是否有一种更简单的方法可以阻止Derivative
的继承人访问某个功能(基类有权访问)?
答案 0 :(得分:1)
您可以使用显式接口实现来隐藏工厂方法。任何客户端仍然可以在转换后调用Create
方法,但至少intellisense不会帮助开发人员。
public interface ISecretFactory<T>
{
T Create(string param);
}
public abstract class Base<T> where T : Base<T>, ISecretFactory<T>
{
public T GetChild()
{
// We are sure type T always implements ISecretFactory<T>
var factory = this as ISecretFactory<T>;
return factory.Create("base param");
}
}
public class Derivative : Base<Derivative>, ISecretFactory<Derivative>
{
public Derivative()
{
}
private Derivative(string param)
{
}
Derivative ISecretFactory<Derivative>.Create(string param)
{
return new Derivative(param);
}
}
public class SecondDerivative : Derivative
{
public void F()
{
// intellisense won't show Create method here.
// But 'this as ISecretFactory<Derivative>' trick still works.
}
}
答案 1 :(得分:0)
通过将ComplexComputation
移动到基类的构造函数并使GetChild
方法抽象为让派生类在那里选择正确的构造函数,可以避免使用附加对象。
但是如何将基础构造函数中的计算值param
返回给调用派生构造函数?可能是使用out
参数修饰符。但是因为在C#5.0中,遗憾的是我们无法在基础构造函数调用之前(或之内)声明变量,我们需要在派生构造函数中获取参数。
public abstract class Base<T> where T : Base<T>
{
public abstract T GetChild();
protected Base(T parent, out string param)
{
param = ComplexComputation();
}
protected Base()
{
}
}
// --- somewhere else: ---
public class Derivative : Base<Derivative>
{
public sealed override Derivative GetChild()
{
string param;
return new Derivative(this, out param);
}
public Derivative() { }
private Derivative(Derivative parent, out string param)
: base(parent, out param)
{
// some configuration
}
}
在我的情况下,我可以将param
从构造函数中移开,而是将其存储在public
属性中。
除了讨厌的必要黑客之外,这种方法对我来说看起来相对干净,但是当GetChild
的多次重载是必要的时候它不会“缩放”。
也许在C#6.0中,可以直接在基础构造函数调用中声明param
。 https://msdn.microsoft.com/de-de/magazine/dn683793.aspx