我真的看不到这里的 Template Method。我看到Visitor pattern。
这是一个例子。
假设你有一堆房子,你需要把它们都漆成黄色。现在你可以:
var houses = ... a list of houses ...
foreach (var house in houses)
{
house.Color = Color.Yellow;
}
但是,您可能希望将动作(在本例中为绘画)抽象为其他东西,而不是总是将房屋涂成黄色。一种解决方案是编写一个负责将房子涂成黄色的类。该课程稍后可以替换为另一个课程,该课程以不同的颜色粉刷房屋,或者对您的房屋进行完全不同的操作,例如添加另一层楼!
输入访客模式。
我将展示一些我一直在使用的通用帮助类和接口。我喜欢泛型。如果你不这样做,请随意滚动你自己的。语义是:“访问者访问可访问者”,以及“可访问者接受访问者”。
public interface IVisitor<in T> where T : IVisitable<T>
{
void Visit(T visitable);
}
public interface IVisitable<out T> where T : IVisitable<T>
{
void Accept(IVisitor<T> visitor);
}
public abstract class Visitable<T> : IVisitable<T> where T : Visitable<T>
{
public void Accept(IVisitor<T> visitor)
{
visitor.Visit((T)this);
}
}
public abstract class VisitableList<T> : List<T>, IVisitable<T> where T : Visitable<T>
{
public void Accept(IVisitor<T> visitor)
{
foreach (var item in this)
{
item.Accept(visitor);
}
}
}
现在我们可以像这样设置我们的房子和我们的房子列表:
public class House : Visitable<House>
{
public Color Color { get; set; }
}
public class Houses : VisitableList<House> {}
现在,访客——我们的画家——可以参观我们可参观的房子:
public class YellowPainter : IVisitor<House>
{
public void Visit(House visitable)
{
visitable.Color = Color.Yellow;
}
}
简单、优雅和single responsibility(!)。
让我们设置房子:
var houses = new Houses();
houses.Add(new House() { Color = Color.Green });
houses.Add(new House() { Color = Color.Blue });
houses.Add(new House() { Color = Color.White });
现在我们已经准备好粉刷我们所有的房子了。只需一个电话:
houses.Accept(new YellowPainter());
...我们所有的房子现在都是黄色的。不错!
我们可以很容易地做到这一点:
houses.Accept(new AdditionalFloorsBuilder(floors: 2));
或者这个:
owlClasses.Accept(new OwlClassVisitor(owlBuilder, ...));
通过这样做,我们将owlClasses 中每个元素的实际“访问”与集合本身的迭代隔离开来。访问不需要修改可访问的。它可以用来只检查可访问的并使用信息来修改完全不同的东西,例如。您可以使用这些信息来提供您的owlBuilder。