我正在实现模板方法模式。客户可以在此模板方法上更改一些设置;但我想阻止模板方法的实现者更改这些设置,因为在这种情况下,他们可能会破坏模板方法(基)类的不变量。如果可能的话,我希望这些东西无法编译。(否则是时候重构策略了:))
例子:
abstract class TemplateMethod
{
// Clients of implementers of this template method change these settings before
// calling GetItems()
public SomeType RootItem { get; set; }
public bool Recursive { get; set; }
protected abstract bool ItemIsWhitelisted(SomeType item);
public IEnumerable<SomeType> GetItems()
{
var stack = new Stack<T>();
stack.Push(RootItem);
while (!stack.empty())
{
var current = stack.Pop();
if (Recursive)
{
foreach (var item in current.Children)
stack.Push(item);
}
if (!ItemIsWhitelisted(current))
yield return current;
}
}
}
class Implementer : TemplateMethod
{
protected override bool ItemIsWhitelisted(SomeType item)
{
Recursive = false; // Oops; TemplateMethod.GetItems didn't expect this
// to change inside ItemIsWhitelisted
return item.CanFrobinate();
}
}
一种方法是重构策略,产生以下结果:
interface IImplementer
{
bool ItemIswhitelisted(SomeType item);
}
sealed class NoLongerATemplateMethod
{
// Clients of implementers of this template method change these settings before
// calling GetItems()
public SomeType RootItem { get; set; }
public bool Recursive { get; set; }
public IImplementer impl { get; set; } // would be private set in real code
public IEnumerable<SomeType> GetItems()
{
var stack = new Stack<T>();
stack.Push(RootItem);
while (!stack.empty())
{
var current = stack.Pop();
if (Recursive)
{
foreach (var item in current.Children)
stack.Push(item);
}
if (!impl.ItemIsWhitelisted(current))
yield return current;
}
}
}
class Implementer : IImplementer
{
public bool ItemIsWhitelisted(SomeType item)
{
Recursive = false; // No longer compiles
return item.CanFrobinate();
}
}
我很好奇是否有一种语言功能可以指示这种约束,而无需将重构应用于策略。